Keresés

Új hozzászólás Aktív témák

  • joysefke

    veterán

    válasz leslie23 #9709 üzenetére

    Két párhozamos dologról volt szó amelyek egymástól valamennyire függetlenek:

    A fontosabb döntés:
    1,
    1a, N layer (Te nyilván háromban gondolkodsz) vs 1b Hexagonal (vagy ahogyan hívni szeretnéd) arch.

    másodjára
    2,
    2a, Generikus Repo/UoW mögé rejtett EF DbContext vs 2b Domain specifikus perzisztencia interfészek (nem tudom a nevüket bocsi)

    Én azt sugalltam, hogy ne próbálj meg tankönyvi N-layert csinálni.

    Ezen felül nekem fenntartásaim vannak azzal kapcsolatban, hogy az DbContext-et bezárjuk egy generikus Repo/UoW mögé és majd az "applikációs réteg" használja a az Insert/Update/ etc metódusokat (az eredeti írásodból azt olvastam ki, hogy erre készülsz) .

    Szóval anélkül, hogy tudnám, hogy egyáltalán mit akarsz csinálni, nekem az alap hozzáállásom egy újabb kis hobbiprojektemhez amiben van ASP meg DB a következő lenne (a nevek szabadon variálhatóak, csak próbáltam beszédes neveket varázsolni):

    MyProjekt.ASP => MyProjekt.Core <= MyProjekt.Ef

    Nincsenek rétegek és nincsen sem teteje sem alja, viszont van közepe meg vannak a többiek. A nyilak a dependencia irányokat mutatják.

    Mindenki a közepét referálja, a közepe viszont nem referál olyan dolgokat amelyektől nem akar függeni. Nem referálja sem a saját EF vagy ASP függő projektjeidet sem magát az ASP vagy EF frameworkot

    Amikor a közepe valamit akar a "széllétől", akkor azt egy saját magában definiált interfészt használva teszi meg

    Ennek két hatása van:
    -a közepe mindenki nélkül, önmagában is fordul, ez megteremti a lehetőségét, hogy könnyedén unit teszteld
    -a közepe a függőségeket (pld EfPerzisztencia) DI formájában (leginkább konstruktoron keresztül) kapja meg, ez pedig megint erősíti a közepének a unit tesztelhetőségét

    Ahhoz, hogy ez megvalósuljon, a dependenciák invertálva vannak:

    Ha ez egy N-layer arch lenne, akkor az "Application layer" referálná a DAL-t (vagy közvetlenül, vagy interfészen keresztül, de az interfész is logikailag a DAL-ban lenne).
    De itt nem, itt ez fordítva van. Itt amit a DAL (ábrán MyProject.Ef)-tól a Core használni akar, az interfész formájában definiálva van, és ez az interfész a "Core" része és a DAL valósítja meg.

    Másrészt a "Core"-ban lévő dolgoknak amelyek valamit akarnak a széllétől (pld perzisztálni) nyilván szükségük van olyan objektumokra amelyek ez meg is tudják csinálni (megvalósítják azt az interfészt amit a "Core" adott osztálya éppen használni akar). Ezek az objektumok DI-jal kerülnek be leginkább mint konstruktor paraméter. A DI konténert a te esetedben az ASP-s template ConfigureServices-ban tudod konfigurálni (ez gyak. az applikáció belépési pontjánál van).

    Visszatérve a konkrét kérdéseidhez:
    -Az ASP-s Controllerek, View-k Modell-ek (azok amelyek a Html-be szállítják az adatot) azok mind az ASP-s projektedbe kerülnek.

    -A Core-ba kerül minden "domain model" (első körben az entitásaid is mindenképpen akár van annotáció rajtuk akár nincs) meg mindenféle logika ami ezeket érinti.

    -A "Core"-ból mindenféle frameworkos stabil osztály felé mehet dependencia, pld a DataAnnotation-t amit korábban felvetettél reálisan nem fog problémát okozni és a tesztelést sem nehezíti meg.

    -Mehet külső dolgok irányába is, ha azok nem nehezítik a tesztelést meg nem akarod őket soha lecserélni. pld Newtonsoft.Json.

    -A "Core" specifikálja interfészekkel, hogy mit kell tudjon a perzisztencia (meg egyéb függőségek amelyektől akar valamit) és ezek az interfészek a core-ban vannak.

    -A külső projektekben lévő függőségek pedig megvalósítják a Core-ban azt/azokat az interfészeket amelyek miatt nekik egyáltalán helyük van a szolutionben.

    Tehát ha maradsz a generikus repositorinál, "2a" akkor a Te általad tervezett ... IPersonRepository, IProductRepository, ... IRepository<T> ... IProductRepository ... IRepository<Product> interfészeid is mind a "Core" ba mennek,

    egy a lényeg, a Core-ba nem kerülhet be EF függőség (tehát az interfészeid metódusainaknak sem lehet EF ben deklarált paramétere, visszatérési értéke). A Repository interfészed konkért megvalósítása viszont az Ef-projektbe kerül.

    Vagy dobod a generikus repository-t ez a "2b" és ekkor a Core-ban nem a fenti teljesen álltalános perzisztencia interfészek lesznek mint hogy az IPersonRepository-n lesz mondjuk egy void Save(Person person), hanem lesz mondjuk egy (csak a példa kedvéért)
    IPersonCommands
    {
    void SetProfileImage(int personId, Picture  picture);

    ugyanúgy a "Core"-ban, ezt meg mondjuk megvalósítja egy EfPersonCommands az Ef projektben. Szintén csak a példa kedvéért:

    EfPersonCommands: IPersonCommands
    {
    IDbContextFactory<PersonContext> _factory
    // vagy Optionst injektálsz (az a preferált ebből szintén elő tudsz állítani Contextet amikor kell) vagy factoryt, mindkét opció tiszta lesz DI-jal,
    EfPersonCommands(IDbContextFactory<PersonContext> factory)
    {
    _factory = factory // throw if null..
    }

    void SetProfileImage(int personId, Picture  picture)
    {
    using var context = _factory.Create();
    //csinálsz valamit

    context.Save() <= tranzakció
    } <= dbcontext dispose
    }

    A kliens pontosan azt kapja amire szüksége van (cserébe potenciálisan több metódusod lesz), a megvalósításba már bele van csomagolva a tranzakció.
    2a vs 2b az részletkérdés (könnyen tudsz változtatni bármelyik irányban), 1a vs 1b viszont egyáltalán nem.

Új hozzászólás Aktív témák

Hirdetés