Jeden model do edycji a inny do zapisania - gdzie przepisywanie danych?

0

Spotkałem się na forum z opiniami (np @somekind) żeby do wyświetlenia danych używać innego modelu niż do zapisywania do bazy. Nie do końca łapię o co chodzi. Rozumiem to tak

  1. mam ViewModelEdit który przekazuję do widoku
  2. użytkownik na widoku edytuje sobie potrzebne dane
  3. dane które mają pójść do bazy przepisuje do ViewModelSave (w którym momencie miałoby się odbyć takie przepisanie ViewModelEdit=>ViewModelSave?)
  4. zapisuję ViewModelSave do bazy

Mógłby ktoś przystępnie to objaśnić na przykładzie?

0

Spotkałem się na forum z opiniami (np @somekind) żeby do wyświetlenia danych używać innego modelu niż do zapisywania do bazy. Nie do końca łapię o co chodzi.

Tak trochę offtop

A jak inaczej bez żadnego innego modelu do wprowadzania danych realizowałbyś aktualizacje danych?

0

No do widoku przekazuje ViewModelEdit i pozniej do bazy tez zapisuje ViewModelEdit

1

Somekindowi chodziło raczej o podział na ReadOnlyViewModel i EditViewModel, który jednocześnie jest SaveModelem. Tak jest w pizzamvc https://github.com/dwdkls/pizzamvc/ i dla mnie brzmi logiczniej :)

2

Masz źle to ponazywane, co może powodować większe zmieszanie. ViewModelEdit powinien nazywać się odpowiednio do funkcji do jakiej jest używany. Samo ViewModelEdit nic nie mówi- edytuj co? Powinno być np. EditUserViewModel. Taki view model jest typem związanym z widokiem, może posiadać np. metadane (atrybuty) o tym jak coś wyświetlać, informacje o walidacji itp. Twoja druga klasa ViewModelSave jest znów źle nazwana. To nie powinien być żaden view model, bo model widoku już masz. To powinien być po prostu Twój model domenowy, czy też encja. Czyli to na czym/za pomocą czego wykonujesz operacje w systemie i co ewentualnie przechowujesz w bazie danych. Dla EditUserViewModel byłby to odpowiednio User.

"Przepisanie" czyli mapowanie może się odbyć np. w kontrolerze, lub w serwisie. Możesz to zrobić ręcznie lub użyć narzędzia takiego jak np. AutoMapper.

EDIT: Drobne sprostowanie. Z mapowaniem chodziło mi o mapowanie typów które nie są modelami domenowymi. Oczywiście nie należy mapować z modelu widoku na model domenowy jeśli np. edytujemy użytkownika.

2
goodfather napisał(a):

Spotkałem się na forum z opiniami (np @somekind) żeby do wyświetlenia danych używać innego modelu niż do zapisywania do bazy. Nie do końca łapię o co chodzi. Rozumiem to tak

  1. mam ViewModelEdit który przekazuję do widoku
  2. użytkownik na widoku edytuje sobie potrzebne dane
  3. dane które mają pójść do bazy przepisuje do ViewModelSave (w którym momencie miałoby się odbyć takie przepisanie ViewModelEdit=>ViewModelSave?)
  4. zapisuję ViewModelSave do bazy

Mógłby ktoś przystępnie to objaśnić na przykładzie?

Ale przecież opisany przez Ciebie scenariusz dotyczy właśnie wyłącznie operacji zapisywania danych.. I nie ma też żadnej potrzeby przepisywania z ViewModelEdit na ViewModelSave.
W stwierdzeniu żeby do wyświetlenia danych używać innego modelu niż do zapisywania chodzi o to, żeby jednego viewmodelu nie używać jednocześnie w operacjach odczytywania danych jak i zapisywania, czyli aby ViewModelEdit nie był używany np. do generowania grida albo w podglądzie szczegółów.

0

Czyli np mam klasę MyViewModel (nie zwracajmy uwagi na nazwenictwo)

  1. mam utworzone kilka klas opisujących tabele w bazie danych, np tabele Order, OrderItem, Customer
  2. do widoku przekazuję MyViewModel w którym mam dane pobrane z kilku tabel z bazy (tabele z pkt 1, oczywiście tylko te dane które są potrzebne w tym widoku).
  3. użytkownik w widoku modyfikuje niektóre dane z tego MyViewModel i zatwierdza te zmiany (np przyciskiem na stronie).
  4. MyViewModel ze zmianami jakie zrobił użytkownik idzie do serwisu który ma to zapisać do bazy
  5. w tym serwisie tworze sobie klasy Order, OrderItem, Customer i przepisuje do nich dane z MyViewModel. Następnie dodaje do context te klasy i wywołuje na nim SaveChanges.

Czy o to chodzi?

1

Tak, chociaż punkt 5 brzmi jakbyś opisywał dodawanie nowych rzeczy a nie edytowanie istniejących. Zakładając że edytujesz istniejące już elementy, to w punkcie 5 po stronie serwera zaladujesz dane z bazy (po IDs elementów w modelu widoku), dokonasz zmian i ponownie je zapiszesz.

Sprawa trochę się komplikuje jeśli Order ma kolekcję OrderItem i chcesz jakieś dodawać/usuwać. Ale to zagadnienie związane ściśle z MVC i wymagało by raczej nowego wątku.

1

@Aventus:

Wysyłasz na widok model np. Order, który zawiera List<OrderItem>, który zawiera np. Guid i nazwę.

Na widoku masz formularz, który poza informacjami dot. order zawiera naszą listę OrderItem, a dokładnie jej abstrakcję

Taki pseudo kod:

@foreach (var item in @Model.OrderItems)
{
	<div class="entry_container" id="@item.Id"> // pojemnik na cały wiersz
		<input type="hidden" name="MyOrderIDsArray[]" value="@item.Id"/> // wystarczy [] - nie trzeba pilnować indexów.
		<input readonly value="@item.Title"/> // jakiś napis
		<button type="button" onclick="remove_div('@item.Id')"; // button do usuwania z listy (type=button aby nie submitnął)
	</div>
}

js:
function remove_div(guid)
{
	 document.getElementById(guid).Remove(); czy coś
}

Gdy wyślę ten formularz, to te wpisy dot. name="MyOrderIDsArray[]" z wartościami value="@item.Id", które nadal są w DOMie zostaną wysłane jako np. List<Guid> do kontrolera, a te które usunąłeś z DOMa javaskryptem nie zostaną.

Później już pozostaje etap wyczyszczenia i przypisania tych OrderItems, które zostały wysłane do kontrolera - List<Guid>

np. order.OrderItems.Clear() i dodawanie 1 by 1 z bazy o Id z listy.

Oczywiście tą fazę nadpisywania wypadałoby jakoś lepiej zrobić + jakieś zabezpieczenia.

Drugie podejście, akurat teraz wpadłem na to:

Można też pójść w drugą stronę i zapisywać tylko te Guidy, które usunąłeś i wysłać listę tych, które chcesz usunąć z kolekcji :)

Zatem:

Masz jeden widok, na którym możesz usuwać (i dodawać, ale to trochę więcej trzeba zrobić) dynamicznie (więc fajnie od strony usera) i zapisujesz wszystko na raz.

1
goodfather napisał(a):

Czyli np mam klasę MyViewModel (nie zwracajmy uwagi na nazwenictwo)

  1. mam utworzone kilka klas opisujących tabele w bazie danych, np tabele Order, OrderItem, Customer
  2. do widoku przekazuję MyViewModel w którym mam dane pobrane z kilku tabel z bazy (tabele z pkt 1, oczywiście tylko te dane które są potrzebne w tym widoku).
  3. użytkownik w widoku modyfikuje niektóre dane z tego MyViewModel i zatwierdza te zmiany (np przyciskiem na stronie).
  4. MyViewModel ze zmianami jakie zrobił użytkownik idzie do serwisu który ma to zapisać do bazy
  5. w tym serwisie tworze sobie klasy Order, OrderItem, Customer i przepisuje do nich dane z MyViewModel. Następnie dodaje do context te klasy i wywołuje na nim SaveChanges.

Czy o to chodzi?

Jeśli pisząc "widok" masz na myśli jakąś stronę służącą do edycji, to tak.

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