ASP MVC - repository potrzebne?

0

Uczę się od niedawna ASP MVC 5 i zajduje wiele sprzecznych informacji w różnych tutorialach np na stronie Microsoftu w tutorialach:

Repository and unit of work patterns

Many developers write code to implement the repository and unit of work patterns as a wrapper around code that works with the Entity Framework. These patterns are intended to create an abstraction layer between the data access layer and the business logic layer of an application. Implementing these patterns can help insulate your application from changes in the data store and can facilitate automated unit testing or test-driven development (TDD). However, writing additional code to implement these patterns is not always the best choice for applications that use EF, for several reasons:

The EF context class itself insulates your code from data-store-specific code.
The EF context class can act as a unit-of-work class for database updates that you do using EF.
Features introduced in Entity Framework 6 make it easier to implement TDD without writing repository code.

W Controllerach używają oni też modelu bespośrednio stworzonego przez Entity Framework, gdzie na innych tutorialach czytalem że jest to duży błąd. Mógłby ktoś kto pracuje w tym i używa Entity Framework 6 z MVC 5 napisać jak to się stosuje w praktyce?

0

U mnie w pracy stosujemy repozyoria, ale moim zdaniem jest to nadmiarowe w przypadku EF, który sam w sobie implementuje ten wzorzec.

0

W przypadku złożonych systemów często posiadasz dane z różnych źródeł np. z web serwisów, jakichś plików XML, bazy danych. Wówczas dobrze mieć odpowiednią warstwę abstrakcji odpowiadającą za dostęp do danych (Data Access Layer) np. poprzez zastosowanie wzorca Repository. Osobiście nie widzę nic złego w przypadku stosowania tego wzorca razem z narzędziem ORM jakim jest Entity Framework. Zaletą takiego rozwiązania jest łatwość testowania takiego kodu. Owszem można się czepiać iż jest to nadmiarowość, ponieważ EF wykorzystuje wzorzec Repository. Każdy DbSet jest naszym repozytorium.

0

Mam w bazie danych 2 tabele w relacji wiele do wielu. Aktorzy(zawiera virtual ICollections<FILM>) i Filmy(zawiera virtual ICollections<Actor>), EF utworzyło mi trzecią AktorFilm z samymi ID obu. W widoku przy tworzeniu np. filmu, chciałbym wyświetlać listę wszystkich aktorów z których będzie można wybrać kilku. Więc utworzyłem ViewModel, który składa się z FILM, lista wszystkich aktorów i lista wybranych. Przy wywołaniu GET tworzę ten ViewModel i pobieram z bazy listę wszystkich aktorów i przekazuję do Widoku. Przy post wyciągam z ViewModel Film, dopisuję do niego jeszcze liste wybranych aktorów i wrzucam do bazy.
I moje pytanie : Czy to wypełnianie ViewModelu np tymi aktorami moge normalnie robić w kontrolerze? Czy powinienem mieć jakąś odzielną warstwę od takiej logiki?

0

W przypadku aplikacji tutoriali często dla ułatwienia nie robi się wielu warstw. Jednak "produkcyjnie" powinieneś traktować kontroler jako głupi komponent tylko wołający inne komponenty, np serwisy, które zajmą się "robotą" lub oddelegują ją jeszcze dalej/niżej (np do repozytoriów, czy z samego DBSetu zaciągną dane).

W skrócie:
Ogólnie - Możesz - bo się da, ale nie powinieneś.
"W pracy":
Nie, nie możesz.

0
AreQrm napisał(a):

W przypadku aplikacji tutoriali często dla ułatwienia nie robi się wielu warstw. Jednak "produkcyjnie" powinieneś traktować kontroler jako głupi komponent tylko wołający inne komponenty, np serwisy, które zajmą się "robotą" lub oddelegują ją jeszcze dalej/niżej (np do repozytoriów, czy z samego DBSetu zaciągną dane).

W skrócie:
Ogólnie - Możesz - bo się da, ale nie powinieneś.
"W pracy":
Nie, nie możesz.

A masz może pod ręką jakiś projekt na githubie w którym jest to wszystko zrobione tak jak bym miał robić "w pracy" bez jakis uproszczeń itp.

5
aut napisał(a):

W Controllerach używają oni też modelu bespośrednio stworzonego przez Entity Framework, gdzie na innych tutorialach czytalem że jest to duży błąd. Mógłby ktoś kto pracuje w tym i używa Entity Framework 6 z MVC 5 napisać jak to się stosuje w praktyce?

Nie ma znaczenia, jakiego ORMa, ani jakiego frameworka używasz. Jeśli chcesz trzymać się wzorca MVC, to w kontrolerze NIE używasz ani repozytoriów, ani obiektu ORMa bezpośrednio. Jedyne, z czego kontroler powinien korzystać to serwis aplikacyjny albo klient webserwisów (jeśli oczywiście taka warstwa fizyczna jest w systemie).

W praktyce częste jest używanie zarówno repozytoriów (które same z siebie w większości przypadków są zbędne) jak i DbContextu w kontrolerach. Jest podejście niepoprawne, rodzące masę problemów wydajnościowych (select n+1, pobieranie zbędnych danych, leniwe ładowanie połowy bazy danych do pamięci) oraz utrudniające rozwój aplikacji. No, ale niestety, u programistów powszechne jest niezrozumienie wzorca MVC i uznawanie tutoriali Microsoftu za wzór architektury aplikacji.

mariano901229 napisał(a):

W przypadku złożonych systemów często posiadasz dane z różnych źródeł np. z web serwisów, jakichś plików XML, bazy danych. Wówczas dobrze mieć odpowiednią warstwę abstrakcji odpowiadającą za dostęp do danych (Data Access Layer) np. poprzez zastosowanie wzorca Repository.

Repository to NIE jest DAL!!!

Repozytorium to obiekt, który daje logice biznesowej imitujący kolekcję interfejs dostępu do obiektów biznesowych. Czyli ma metody w rodzaju Add, Update, Delete i FindBy*. Repozytorium może korzystać z bazy danych, do której dostęp może być realizowany za pomocą innego wzorca, np. ORM (albo np. Table Data Gateway albo Row Data Gateway), a mogą to też być dane trzymane w plikach XML, albo odwołania do zewnętrznego systemu przez webserwisy. Źródło danych jest nieistotne, istotne jest API.

Osobiście nie widzę nic złego w przypadku stosowania tego wzorca razem z narzędziem ORM jakim jest Entity Framework. Zaletą takiego rozwiązania jest łatwość testowania takiego kodu.

Tylko, że od wersji 6 wprowadzono do EF interfejsy, więc można już normalnie mockować kod do testów bez potrzeby tworzenia bezsensownej warstwy pseudorepozytoriów.
Niemniej jednak, w każdym przypadku, najlepiej EF nie używać.

aut2q napisał(a):

Mam w bazie danych 2 tabele w relacji wiele do wielu.

Dwie tabele powiązane wiele do wielu. Tabela jest relacją.

I moje pytanie : Czy to wypełnianie ViewModelu np tymi aktorami moge normalnie robić w kontrolerze? Czy powinienem mieć jakąś odzielną warstwę od takiej logiki?

Cały, gotowy ViewModel powinieneś dostać z serwisu aplikacyjnego. W kontrolerach nie powinno być innej logiki niż sprawdzenie, czy operacja się powiodła i przekierowanie do odpowiedniego widoku.

0

Czyli mogę dodać np. nowy projekt "Service layer" , w jego klasach robić np. wspomniane wyżej wypełnianie FilmViewModel dostepnymi aktorami? A kontroler powinien tylko wywołać jakąś metodę z tego "servisu" która zwróci mu FilmViewModel ?

0

Tak. W tych serwisach możesz korzystać z DbContextu bezpośrednio, bez żadnych repozytoriów. Dopóki jest to prosty CRUD, a nie DDD, to repozytoria nie są potrzebne.

0

A gdzie powinienem trzymać te wszystkie ViewModele? Bo mam teraz 3 projekty Domain(w nim mam Entities i DbContext) , WebUI w nim mam controllery i widoki i do tej pory mialem w nim ViewModele, ale jak utworzyłem 3 projekt Service, w którym np tworze te ViewModele, to musiałbym w nim mieć referencje do WebUI, a nie jest to przypadkiem sprzeczne z sensem istnienia w ogóle tego Service. Myślałem że ma na celu on to żebym mógł wykorzystać go np. w innym projekcie np jakies WPF.

0

Dlaczego miałbyś mieć w Serwisach referencję do WebUI? Raczej odwrotnie.

0
 public class Actor
    {
        public int ID { get; set; }
        public string FirstName { get; set; }
        .

        public virtual ICollection<Movie> Movies { get; set; }
    }
 

Przepraszam za double posta, ale nie moge edytowac tamtego :(

 
    public class Movie
    {
       public int ID { get; set; }
       public string Title { get; set; }
       public DateTime ReleaseDate { get; set; }
       public virtual ICollection<Actor> Actors { get; set; }
       public virtual ICollection<Genre> Genres { get; set; }
    }

No więc mam te 2 Entities.
I mam

 
   public class MovieViewModel
    {
        public Movie Movie { get; set; }                 
        public List<int> selectedActors { get; set; } 
        public virtual IEnumerable<Actor> Actors { get; set; }
        public virtual IEnumerable<Genre> Genres { get; set; }
}

Więc przy przekazywaniu MovieVIewModel do WIdoku przez Kontroler muszę wypełnić ta liste Actors wszystkimi aktorami. Wyżej napisałeś, że powinienem to w Serwisie zrobić, więc żebym mógł to zrobić w serwisie to serwis musi mieć dostęp do tego MovieViewModel czyli referencje do projektu WebUI w którm trzymam te ViewModel? BO już sam nie wiem czy kompletnie coś źle rozumiem jak to powinno wyglądać.

0

Ja robię tak:

  1. Model - obiekty mapowane na bazę (żadnych zależności od ORM)
  2. Contracts - ViewModele i interfejsy Serwisów
  3. Application - implementacje Serwisów, w których korzystam z ORMa
  4. Web - aplikacja MVC

Application ma w referencjach Model i Contracts, Web ma w referencjach tylko Contracts.

PS Edycja jest dostępna dla zarejestrowanych użytkowników, niby na jakiej zasadzie anonim miałby edytować? :)

0
somekind napisał(a):

Application ma w referencjach Model i Contracts, Web ma w referencjach tylko Contracts.

Ale wtedy jak mam ogarnąć dostęp do implementacji jeżeli Web ma w referencjach tylko Contracts?

0

Kontener IoC może wczytać wszystkie dllki i porejestrować zależności, a w projekcie webowym wszystko jest wyciągane.

1

Repozytorium w sumie nie jest zawsze aż tak bardzo potrzebne. Mało tego - czasami może wręcz niepotrzebnie skomplikować kod. Zamiast tego wykorzystaj serwisy. Ja tam nie palę się jakoś specjalnie do wykorzystywania repozytoriów.

0

@somekind pozwól, że będę Cię ciągnął za język:

Kontener IoC może wczytać wszystkie dllki i porejestrować zależności, a w projekcie webowym wszystko jest wyciągane.
Możesz opisać jak to jest technicznie robione?

W jakim projekcie korzystasz z kontenera IoC - jest to aplikacja webowa, tak? Z jakiego kontenera IoC korzystasz i co to znaczy, że kontener "wczytuje" wszystkie dllki -> rozumiem, że nie jest to równoznaczne z podpinaniem wszystkich referencji do aplikacji webowej?

0

Podpinam się pod pytanie, bo też nie za bardzo rozumiem gdzie i jak IoC może wczytywać dllki?

Młodszy Programista napisał(a):

@somekind pozwól, że będę Cię ciągnął za język:

Kontener IoC może wczytać wszystkie dllki i porejestrować zależności, a w projekcie webowym wszystko jest wyciągane.
Możesz opisać jak to jest technicznie robione?

W jakim projekcie korzystasz z kontenera IoC - jest to aplikacja webowa, tak? Z jakiego kontenera IoC korzystasz i co to znaczy, że kontener "wczytuje" wszystkie dllki -> rozumiem, że nie jest to równoznaczne z podpinaniem wszystkich referencji do aplikacji webowej?

0

Poczytajcie w tym wątku

2

Każda dllka (która tego potrebuje) niech sobie implementuje: http://docs.autofac.org/en/latest/configuration/modules.html w którym zarejestruje swoje typy, a potem w projekcie startowym:

var builder = new ContainerBuilder();
var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
builder.RegisterAssemblyModules(loadedAssemblies);
var container = builder.Build();

DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

A jeśli czegoś nie ma w AppDomain, to zawsze można zrobić Assembly.Load. I nie trzeba referencji w projekcie startowym - to jest właśnie piękne.

1 użytkowników online, w tym zalogowanych: 0, gości: 1