This shows you the differences between two versions of the page.
pw:laboratoare:02 [2023/02/23 11:39] ciprian.dobre [Informatii suplimentare pentru cine doreste] |
pw:laboratoare:02 [2023/03/13 18:00] (current) ciprian.dobre [Dependency injection] |
||
---|---|---|---|
Line 11: | Line 11: | ||
Un motiv pentru care limbaje cum sunt Java si C# sunt populare pentru dezvoltarea de aplicatii este faptul ca suporta reflexie la runtime, adica programul la runtime poate face introspectie si poate, de exemplu, sa creeze instante de obiecte fara sa fie explicit programat in acest sens. | Un motiv pentru care limbaje cum sunt Java si C# sunt populare pentru dezvoltarea de aplicatii este faptul ca suporta reflexie la runtime, adica programul la runtime poate face introspectie si poate, de exemplu, sa creeze instante de obiecte fara sa fie explicit programat in acest sens. | ||
- | Acest lucru a ajutat la implementarea de dependency injection in aceste limbaje ce se rezuma doar la faptul ca la runtime componentele sunt instantiate rand pe rand de la cele mai simple la cele mai complexe iar instantele componenteleor sunt pasate ca paramentri pentru instantierea altor componente. | + | Acest lucru a ajutat la implementarea de dependency injection in aceste limbaje ce se rezuma doar la faptul ca la runtime componentele sunt instantiate rand pe rand de la cele mai simple la cele mai complexe iar instantele componentelor sunt pasate ca paramentri pentru instantierea altor componente. |
In exemplul de mai jos se poate vedea cum este declaranta o componeta, parametri dati la constructor sunt pasati de framework atunci cand se cere aceasta componenta, observati ca parametri sunt interfete. De obicei se injecteaza interfete, nu implementari efective motivul fiind ca pot exista mai multe implementari pentru o interfata care pot fi schimbate in functie de necesitati cum ar fi pentru testare, de exemplu se poate inlocui implementarea de productie cu una de test pentru interceptarea apelurilor de metode ale acelui serviciu. | In exemplul de mai jos se poate vedea cum este declaranta o componeta, parametri dati la constructor sunt pasati de framework atunci cand se cere aceasta componenta, observati ca parametri sunt interfete. De obicei se injecteaza interfete, nu implementari efective motivul fiind ca pot exista mai multe implementari pentru o interfata care pot fi schimbate in functie de necesitati cum ar fi pentru testare, de exemplu se poate inlocui implementarea de productie cu una de test pentru interceptarea apelurilor de metode ale acelui serviciu. | ||
Line 69: | Line 69: | ||
De mentionat, exista 3 tipuri de lifetime pentru instantele componentelor, anume: | De mentionat, exista 3 tipuri de lifetime pentru instantele componentelor, anume: | ||
* **Singleton** – pe durata programului doar o singura instanta a acelei componente este instantiata, de fiecare data cand se cere componenta aceiasi instanta este returnata. Un exmplu este ILogger care este instantiat o singura data pentru fiecare parametru generic. | * **Singleton** – pe durata programului doar o singura instanta a acelei componente este instantiata, de fiecare data cand se cere componenta aceiasi instanta este returnata. Un exmplu este ILogger care este instantiat o singura data pentru fiecare parametru generic. | ||
- | * **Transient** – de fiecare data cand se cere o componenta se returneaza o noua instanta. Exemple de componente transient sunt controllerele, la fiecare cerere HTTP o noua instanta de controller este create pentru tratarea cererii. | + | * **Transient** – de fiecare data cand se cere o componenta se returneaza o noua instanta. Exemple de componente transient sunt controllerele, la fiecare cerere HTTP o noua instanta de controller este creata pentru tratarea cererii. |
* **Scoped** – instantele returnate sunt unice pe fiecare scope. Un exemplu este contextul de baza de date. | * **Scoped** – instantele returnate sunt unice pe fiecare scope. Un exemplu este contextul de baza de date. | ||
Line 194: | Line 194: | ||
<code>dotnet ef migrations add <nume_migrare> --context <nume_clasa_context> --project <proiect_cu_migrarile> --startup-project <proiect_cu_startup></code> | <code>dotnet ef migrations add <nume_migrare> --context <nume_clasa_context> --project <proiect_cu_migrarile> --startup-project <proiect_cu_startup></code> | ||
- | In codul din laborator migrarile o data create for fi aplicate automat la prima cerere facuta catre baza de date. | + | In codul din laborator migrarile o data create for fi aplicate automat la prima cerere facuta catre baza de date. Pentru mai multe informatii despre migrari si uneltele in linie de comanda puteti consulta documentatia de [[https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/?tabs=dotnet-core-cli|aici]]. |
===== Informatii suplimentare pentru cine doreste ===== | ===== Informatii suplimentare pentru cine doreste ===== | ||
Line 202: | Line 202: | ||
<code> | <code> | ||
var search = "test"; | var search = "test"; | ||
- | await DbContext.Set<UserFile>().Where(e => EF.Functions.Like(e.Name, $"%{search}%")).OrderByDescending(e => e.CreatedAt).Select(e => new UserFileDTO | + | await DbContext.Set<UserFile>() |
+ | .Where(e => EF.Functions.Like(e.Name, $"%{search}%")) | ||
+ | .OrderByDescending(e => e.CreatedAt) | ||
+ | .Select(e => new UserFileDTO | ||
{ | { | ||
Id = e.Id, | Id = e.Id, | ||
Line 221: | Line 224: | ||
<code> | <code> | ||
select uf."Id", uf."Name", uf."Description", uf."CreatedAt", uf."UpdatedAt", u."Id", u."Email", u."Name", u."Role" from "UserFile" uf | select uf."Id", uf."Name", uf."Description", uf."CreatedAt", uf."UpdatedAt", u."Id", u."Email", u."Name", u."Role" from "UserFile" uf | ||
- | join "User" u on u."Id" = uf."UserId" | + | left join "User" u on u."Id" = uf."UserId" |
where uf."Name" like '%test%' | where uf."Name" like '%test%' | ||
order by uf."CreatedAt" desc | order by uf."CreatedAt" desc | ||
Line 234: | Line 237: | ||
Este nerecomandat sa fie expuse entitatile bazei de date in controller, de aceia cel mai bine este ca entitatile sa fie transformate/mapate in **DTO**-uri (**Data Transfer Objects**), adica obiecte simple care doar transfera informatiile din entitati si care pot fi consumate de garbage colletor independent de contextul bazei de date. De asemenea, nu toate informatiile din entitate pot fi necesare sau se doresc a fi expuse in fara serviciilor si este mai bine sa fie folosite DTO-uri si pentru securitatea aplicatiei. | Este nerecomandat sa fie expuse entitatile bazei de date in controller, de aceia cel mai bine este ca entitatile sa fie transformate/mapate in **DTO**-uri (**Data Transfer Objects**), adica obiecte simple care doar transfera informatiile din entitati si care pot fi consumate de garbage colletor independent de contextul bazei de date. De asemenea, nu toate informatiile din entitate pot fi necesare sau se doresc a fi expuse in fara serviciilor si este mai bine sa fie folosite DTO-uri si pentru securitatea aplicatiei. | ||
- | ===== Informatii suplimentare pentru cine doreste ===== | + | ===== Sarcini laborator ===== |
+ | |||
+ | Descarcati codul din laborator de pe [[https://gitlab.com/mobylabwebprogramming/dotnetbackend|Gitlab]] si urmatiti urmatoarele tipuri de clase: | ||
+ | * Entitati | ||
+ | * Configurari de entitati | ||
+ | * Specificatii | ||
+ | * Repository | ||
+ | |||
+ | Creati prima migrare numita **InitialCreate** cu comanda de **dotnet-ef** si rulati proiectul cu baza de date pornita. Conectati-va la baza de date si urmariti schema bazei de date. | ||
+ | |||
+ | Incercati sa adaugati propriile entitati si creati noi migrari. Puteti de acum sa va creati schema bazei de date pentru proiect. | ||