IoC a Entity Framework rubrika: Programování: .Net

7 harrison314
položil/-a 5.12.2016
 
upravil/-a 5.12.2016

Zdravím,
zaujíma ma ako v aplikačnej vrstve riešite pristup ku Entity Frameworku DB kontextu pomocou IoC kontaineru.

Skúšal som niekoľko postupov, ale žiaden mi nesedel. Hlavne by som chcel mať možnosť explicitne používať kontext v usingu, poprípade ho vnárať a mať možnosť testovať aplikačnú vrstvu.

Moja otázka znie: Ako používate Entity Framework v aplikačnej vrstve a aku abstrakciu nad nim robiť v aplikackcih, v ktorych vyuzivam IoC kontainer?

Co som skusal:

  • Datovu vrstvu uplne zakryvajucu EF ako sluzby nad uloziskom dat (ked pouzivam SQL-ko, tak sa mi to osvedcilo, no pri EF to len mapuje a je s tym vela pisania a aplikacna vrtsva mi na mnohych miestach zostala prazdna)
  • Injektovanie DB kontextu do sluzieb aplikacnej vrstvy (to je principailne zle)
  • Instancovanie DB kontextu v aplikacnej vrstve (clovek sa toho nezbavi a je to netestovatelne)
  • Dost som uvazoval o genrickych repozitorys, ale neviem.
    • PS: Nemyslim to tak, ze priamo v APlikacnej vrstve chcem mat navesany EF ale: Databaza -Entity Framework - nejaka magia - Aplikacna vrtsva - Prezentacna vrstva
odkaz
3 SebastianBusek
odpověděl/-a 9.12.2016
 
upravil/-a 9.12.2016

Ahoj, odpovím za .net core a svou architekturu.

Předně: napsal jsem si vlastní implementaci Unit of work (aplikovatelné jak pro EF6 tak i EF Core), kterou v mírně pozměněné podobě používáme na aktuálním projektu a na nejspíš půjde i do produkce.
Osobně musím registrovat IDbContextFactory, DbContextOptions, UnitOfWork (IUnitOfWorkFactory + IUnitOfWorkManager) a konečně IRepository<TEntity, TKey>, kde IRepository je úplně jednoduchý interface

namespace Idea.Repository
{
    public interface IRepository<TEntity, in TKey> : IQueryExecuter<TEntity>
    {
        TEntity Find(TKey id);
        void Create(TEntity entity);
        void Update(TEntity entity);
        void Delete(TEntity entity);
 
        Task<TEntity> FindAsync(TKey id);
        Task CreateAsync(TEntity entity);
        Task UpdateAsync(TEntity entity);
        Task DeleteAsync(TEntity entity);
    }
}

a na dotazování používám domain queries

namespace Idea.Query.EntityFrameworkCore
{
    public abstract class Query<TEntity, TKey>
        where TEntity : IEntity<TKey>
    {
        protected DbContext Context { get; private set; }
 
        protected abstract IQueryable<TEntity> CreateQuery();
 
        public IReadOnlyCollection<TEntity> Execute(IUnitOfWork uow)
        {
            // validation + getting DbContext from uow
 
            return new ReadOnlyCollection<TEntity>(CreateQuery().ToList());
        }
    }
}

S tím, že většina mých aplikací je dělená do vrstev, nejčastěji používám WebApi > Orchestration > Service a samotné service využívají služeb IRepository a Query. Zkoušel jsem na jednom středně velkém projektu Onion architecture a nebylo to úplně špatné.

Důvod proč to takthle dělám je testovatelnost a taky si myslím, že tím, že vystavením Expression<Func<TEntity, TKey>> pro filtry, ordering, ... přenáším čast logiky na klienta a tím porušuji zapouzdření.

Komentáře

  • harrison314 : Mas to obodobne ako tu https://github.com/riganti/infrastructure . 9.12.2016
  • harrison314 : Ako prenostelnost domian query mas na ne nejaku hromadnu factory? A ako riesis ked vysledkom query nema byt kolekcia entit, ale napriklad vysledok joinu, alebo projekcia? 9.12.2016

Pro zobrazení všech 4 odpovědí se prosím přihlaste:

Rychlé přihlášení přes sociální sítě:

Nebo se přihlaste jménem a heslem:

Zadejte prosím svou e-mailovou adresu.
Zadejte své heslo.