Czy aplikacja ASP.NET MVC powinna bezpośrednio używać Entity Framework jako modelu?

22

Buduję swoją pierwszą aplikację MVC w Visual Studio 2013 (MVC 5) i jestem trochę niejasny, jak najlepiej skonfigurować mój model.

Wygenerowałem model struktury encji przy użyciu kodu najpierw z istniejącej bazy danych. Moim pierwszym instynktem było stworzenie pewnych klas pośrednich, które byłyby modelem używanym przez widoki i aby te klasy działały z klasami struktury encji.

Kiedy pisałem klasy pośrednie, zdałem sobie sprawę, że w większości po prostu ponownie wdrażam wiele rzeczy, które klasy EF już zrobiły tylko z okazjonalnym prywatnym ustawiaczem lub przesyłałem z jednego typu danych na inny. Więc to wydawało się marnotrawstwem.

Czy ogólną zasadą jest bezpośrednie używanie klas struktury encji jako modelu dla aplikacji MVC? Czy jest jakaś korzyść, której mi brakuje w budowaniu tych klas pośrednich?

Mike D.
źródło
Jeśli używałeś kodu najpierw, to nie istniała baza danych, prawda?
Isaac Kleinman
1
Za pomocą EF 6.1+ możesz wygenerować model z pierwszym kodem z istniejącej bazy danych. Zobacz ten artykuł MSDN: msdn.microsoft.com/en-au/data/jj200620.aspx
Mike D.

Odpowiedzi:

23

W moich aplikacjach zawsze rozdzielałem różne rzeczy dla różnych baz danych (Entity Framework) i MVC. Podzieliłem je również na różne projekty:

  • Example.Entities - zawiera moje byty dla EF i kontekst DB dla dostępu do nich.
  • Przykład Modele - zawiera modele MVC.
  • Example.Web - aplikacja internetowa. Zależy zarówno od Example.Domain, jak i Example.Models.

Zamiast przechowywania odniesień do innych obiektów, takich jak jednostki domeny, modele MVC przechowują identyfikatory jako liczby całkowite.

Kiedy przychodzi żądanie GET dla strony, kontroler MVC wykonuje zapytanie do bazy danych, które zwraca jednostkę. Napisałem metody „konwertera”, które pobierają jednostkę domeny i przekształcają ją w model MVC. Istnieją inne metody, które działają odwrotnie (od modelu MVC do encji domeny). Model zostaje następnie przekazany do widoku, a tym samym do klienta.

Kiedy przychodzi żądanie POST, kontroler MVC otrzymuje model MVC. Metoda konwertera konwertuje to na jednostkę domeny. Ta metoda wykonuje również wszelkie weryfikacje, których nie można wyrazić jako atrybuty, i upewnia się, że jeśli jednostka domeny już istnieje, to ją aktualizujemy, a nie otrzymujemy nową. Metody zwykle wyglądają mniej więcej tak:

public class PersonConverter
{
    public MyDatabaseContext _db;

    public PersonEntity Convert(PersonModel source)
    {
         PersonEntity destination = _db.People.Find(source.ID);

         if(destination == null)
             destination = new PersonEntity();

         destination.Name = source.Name;
         destination.Organisation = _db.Organisations.Find(source.OrganisationID);
         //etc

         return destination;
    }

    public PersonModel Convert(PersonEntity source)
    {
         PersonModel destination = new PersonModel()
         {
             Name = source.Name,
             OrganisationID = source.Organisation.ID,
             //etc
         };

         return destination;
    }
}

Korzystając z tych metod, usuwam duplikację, która w innym przypadku wystąpiłaby w każdym kontrolerze. Zastosowanie generycznych może jeszcze bardziej zduplikować rzeczy.

Robienie rzeczy w ten sposób zapewnia wiele korzyści:

  • Możesz dostosować model do konkretnego widoku lub akcji. Załóżmy, że masz formularz rejestracyjny dla osoby, która po przesłaniu tworzy wiele różnych podmiotów (osoba, organizacja, adres). Bez osobnych modeli MVC będzie to bardzo trudne.
  • Jeśli muszę przekazać do widoku więcej informacji, niż byłoby to dostępne tylko w encji, lub połączyć dwie encje w jeden model, moje cenne modele baz danych nigdy nie zostaną zmienione.
  • Jeśli kiedykolwiek serializujesz model MVC jako JSON lub XML, otrzymasz tylko natychmiastowy serializowany model, a nie wszystkie inne podmioty powiązane z tym modelem.
Jack Scott
źródło
Dobra odpowiedź, poleciłbym użycie ValueInjector lub czegoś podobnego (osobiście nienawidziłem automappera) zamiast ręcznego mapowania właściwości z jednej klasy do drugiej.
Rocklan
1
Zamiast dodawać osobną odpowiedź, skomentuję tutaj, że w praktyce DDD twoje „konwertery” i osobne modele widoku będą uważane za część warstwy usługi aplikacji. Zasadniczo pozwala na to, aby Twój model domeny był tak złożony, jak to konieczne, jednocześnie ukrywając tę ​​złożoność przed aplikacją. Chroni również aplikację przed zmianą z powodu zmiany modelu domeny. ASL obsługuje tłumaczenie.
Michael Brown
Więc dzwonisz do każdego modelu, który masz w PersonModel (tj. Obiekt Organizacji), aby uzyskać informacje o tym modelu? Załóżmy, że masz formularz służący do aktualizacji informacji o osobie i organizacji, czy miałbyś dodatkowe połączenie podczas aktualizacji Organizacji? Używam przechowywanych proc, więc czy nie mogę wysłać wszystkich atrybutów modelu i wszystkich zawierających atrybuty modelu naraz?
Luminous
1
Jak poradziłbyś sobie z odwzorowaniem kolekcji? To wydaje się być znacznie bardziej skomplikowane w EF6, ponieważ nie można już po prostu utworzyć nowej listy bytów z aktualizacjami, ponieważ to po prostu odtwarza wszystko ...
Gerard Wilkinson
2
Zamiast pisać własne klasy konwerterów, zaleciłbym użycie biblioteki Automapper, która została napisana w celu rozwiązania tego problemu. Dojrzał dużo od 2014 roku!
BenSmith,
6

Powiedziałbym, że to naprawdę zależy od twojej aplikacji. Czy robi to po prostu czysty CRUD, bez logiki biznesowej? Następnie użyłbym modeli EF bezpośrednio w moich widokach.

W większości przypadków dotyczy to przynajmniej logiki biznesowej, a następnie dobrym pomysłem może być warstwa między modelami danych / EF a widokiem. W takim przypadku może być właściwe wykonanie „CQRS-lite” (patrz poniżej) i użycie różnych modeli do i z kontrolera. Przez większość czasu czytane modele są o wiele „grubsze” niż modele zapisu…

Jeśli jednak aplikacja zawiera dużo logiki biznesowej i / lub wymaga dużej skali, zaimplementowałbym przynajmniej jej rdzeń za pomocą CQRS (segregacja odpowiedzialności za zapytania), DDD (Domain Driven Design) i ewentualnie Sourcing zdarzeń. Następnie EF może być użyty jako fasada modelu do odczytu.

Pamiętaj również, że nie musisz trzymać się jednej strategii / wzoru dla całej aplikacji, niektóre obszary mogą być czystym CRUD, a inne mogą zawierać dużo logiki biznesowej ...

jhdrn
źródło