Każdy artykuł znaleziony w Internecie na temat korzystania z ViewModels i wykorzystania Automappera zawiera wytyczne dotyczące mapowania kierunku „Kontroler -> Widok”. Bierzesz model domeny wraz ze wszystkimi listami wyboru do jednego wyspecjalizowanego ViewModel i przekazujesz go do widoku. To jasne i dobrze.
Widok ma formę i ostatecznie jesteśmy w akcji POST. W tym miejscu na scenę pojawiają się wszystkie Segregatory Modelu wraz z [oczywiście] innym modelem Widoku, który jest [oczywiście] powiązany z oryginalnym ViewModel przynajmniej w części konwencji nazewnictwa w celu powiązania i walidacji.
Jak odwzorować to na swój model domeny?
Niech to będzie akcja wstawiania, moglibyśmy użyć tego samego Automappera. Ale co, jeśli byłaby to aktualizacja? Musimy pobrać naszą jednostkę domeny z repozytorium, zaktualizować jej właściwości zgodnie z wartościami w modelu ViewModel i zapisać w repozytorium.
DODATEK 1 (9 lutego 2010): Czasami przypisanie właściwości Modelu nie wystarczy. Należy podjąć pewne działania przeciwko modelowi domeny zgodnie z wartościami modelu widoku. To znaczy, niektóre metody powinny być wywoływane w modelu domeny. Prawdopodobnie powinien istnieć rodzaj warstwy usługi aplikacji, która znajduje się między kontrolerem a domeną, aby przetwarzać modele widoku ...
Jak zorganizować ten kod i gdzie go umieścić, aby osiągnąć następujące cele?
- utrzymuj kontrolery cienkie
- honorować praktykę SoC
- postępuj zgodnie z zasadami projektowania opartego na domenie
- być SUCHY
- ciąg dalszy nastąpi ...
źródło
Narzędzia takie jak AutoMapper mogą służyć do aktualizowania istniejącego obiektu danymi z obiektu źródłowego. Akcja kontrolera do aktualizacji może wyglądać następująco:
[HttpPost] public ActionResult Update(MyViewModel viewModel) { MyDataModel dataModel = this.DataRepository.GetMyData(viewModel.Id); Mapper<MyViewModel, MyDataModel>(viewModel, dataModel); this.Repostitory.SaveMyData(dataModel); return View(viewModel); }
Oprócz tego, co widać w powyższym fragmencie:
Akcja kontrolera jest dość cienka i obawy są oddzielone: problemy z mapowaniem są rozwiązywane w konfiguracji AutoMapper, walidacja jest wykonywana przez ModelBinder, a dostęp do danych przez Repository.
źródło
Chciałbym powiedzieć, że ponownie używasz terminu ViewModel dla obu kierunków interakcji z klientem. Jeśli przeczytałeś wystarczająco dużo kodu ASP.NET MVC w środowisku naturalnym, prawdopodobnie zauważyłeś różnicę między ViewModel i EditModel. Myślę, że to ważne.
ViewModel reprezentuje wszystkie informacje wymagane do renderowania widoku. Może to obejmować dane renderowane w statycznych, nieinteraktywnych miejscach, a także dane wyłącznie w celu sprawdzenia, aby zdecydować, co dokładnie renderować. Akcja GET kontrolera jest ogólnie odpowiedzialna za pakowanie ViewModel dla jego widoku.
EditModel (lub może ActionModel) reprezentuje dane wymagane do wykonania akcji, którą użytkownik chciał wykonać dla tego testu POST. Więc EditModel naprawdę próbuje opisać akcję. To prawdopodobnie wykluczy niektóre dane z ViewModel i chociaż są powiązane, myślę, że ważne jest, aby zdać sobie sprawę, że rzeczywiście są różne.
Jeden pomysł
To powiedziawszy, możesz bardzo łatwo mieć konfigurację AutoMapper do przejścia z Model -> ViewModel i inną, aby przejść z EditModel -> Model. Następnie różne akcje kontrolera muszą po prostu używać AutoMapper. Do diabła, EditModel może mieć na sobie funkcje do walidacji jego właściwości względem modelu i zastosowania tych wartości do samego modelu. Nie robi nic innego i masz ModelBinders w MVC, aby mimo wszystko zamapować żądanie na EditModel.
Inny pomysł
Poza tym ostatnio zastanawiałem się nad tym, co działa na podstawie idei ActionModelu, ponieważ klient wysyła do Ciebie z powrotem opis kilku działań, które wykonał użytkownik, a nie tylko jedna duża porcja danych. Z pewnością wymagałoby to trochę Javascript po stronie klienta, ale myślę, że pomysł jest intrygujący.
Zasadniczo, gdy użytkownik wykonuje akcje na wyświetlonym ekranie, Javascript zaczyna tworzyć listę obiektów akcji. Przykładem może być to, że użytkownik jest na ekranie informacji o pracowniku. Aktualizują nazwisko i dodają nowy adres, ponieważ pracownik był niedawno żonaty. Pod osłonami daje to
ChangeEmployeeName
a iAddEmployeeMailingAddress
obiekty do listy. Użytkownik klika „Zapisz”, aby zatwierdzić zmiany, a Ty przesyłasz listę dwóch obiektów, z których każdy zawiera tylko informacje potrzebne do wykonania każdej akcji.Potrzebowałbyś bardziej inteligentnego ModelBinder niż domyślny, ale dobry serializator JSON powinien być w stanie zająć się mapowaniem obiektów akcji po stronie klienta na obiekty po stronie serwera. Te po stronie serwera (jeśli jesteś w środowisku dwuwarstwowym) mogą łatwo mieć metody, które zakończyłyby akcję na modelu, z którym pracują. Tak więc akcja kontrolera kończy się po prostu uzyskaniem identyfikatora instancji Model do ściągnięcia i listy działań do wykonania na niej. Albo akcje mają w sobie identyfikator, który je bardzo rozdziela.
Więc może coś takiego zostanie zrealizowane po stronie serwera:
public interface IUserAction<TModel> { long ModelId { get; set; } IEnumerable<string> Validate(TModel model); void Complete(TModel model); } [Transaction] //just assuming some sort of 2-tier with transactions handled by filter public ActionResult Save(IEnumerable<IUserAction<Employee>> actions) { var errors = new List<string>(); foreach( var action in actions ) { // relying on ORM's identity map to prevent multiple database hits var employee = _employeeRepository.Get(action.ModelId); errors.AddRange(action.Validate(employee)); } // handle error cases possibly rendering view with them foreach( var action in editModel.UserActions ) { var employee = _employeeRepository.Get(action.ModelId); action.Complete(employee); // against relying on ORMs ability to properly generate SQL and batch changes _employeeRepository.Update(employee); } // render the success view }
To naprawdę sprawia, że akcja wysyłania zwrotnego jest dość ogólna, ponieważ opierasz się na swoim ModelBinder, aby uzyskać poprawną instancję IUserAction i instancję IUserAction w celu wykonania prawidłowej logiki lub (bardziej prawdopodobne) wywołania modelu z informacjami.
Jeśli pracujesz w środowisku 3-warstwowym, IUserAction może być po prostu prostym DTO do wykonania przez granicę i wykonania w podobnej metodzie w warstwie aplikacji. W zależności od tego, jak zrobisz tę warstwę, można ją bardzo łatwo podzielić i nadal pozostać w transakcji (przychodzi na myśl żądanie / odpowiedź Agathy i wykorzystanie mapy tożsamości DI i NHibernate).
W każdym razie jestem pewien, że nie jest to doskonały pomysł, wymagałoby to trochę JS po stronie klienta do zarządzania, a nie byłem jeszcze w stanie zrobić projektu, aby zobaczyć, jak się rozwija, ale post próbował pomyśleć o tym, jak dostać się tam iz powrotem, więc pomyślałem, że przedstawię swoje myśli. Mam nadzieję, że to pomoże i chciałbym usłyszeć o innych sposobach zarządzania interakcjami.
źródło
Nie potrzebujesz mapowania modelu widoku do domeny, ponieważ model widoku może zostać utworzony więcej niż model domeny. Modele widoków zoptymalizowane pod kątem ekranu (UI) i inne niż model domeny.
http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/
źródło