Czy używając EF muszę sięgać trzy razy do bazy żeby zaktualizować dane?

0

Czy używając EF muszę sięgać dwa razy do bazy żeby zaktualizować dane? Mam np osobę, której chcę zaktualizować imię.
Wizyty w bazie pokazałem pogrubioną czcionką.

  1. Aplikacja uruchamia się i robi do bazy select po dane osoby. Baza zwraca te dane.
  2. Przekazuję co mi potrzebne do warstwy wyżej i wyświetlam użytkownikowi dan osoby.
  3. Użytkownik z interfejsu aplikacji zmienia imię osobie.
  4. Następnie wybiera opcję zapisu zmiany.
  5. Znowu muszę zrobić w EF select do bazy zeby wyciągnąć obiekt który ma zostać zmodyfikowany

var personToModify = await context.People.FirstOrDefaultAsync(p=> p.id == id);

  1. do pobranego obiektu przypisuje nowe imię

personToModify.Name = name;

  1. Zapisuję zmianę do bazy

await context.SaveChangesAsync();

Czyli łącznie są 3 wycieczki do bazy. Czy tak to ma wyglądać jeśli korzystam z EF? Pytanie pojawiło mi się w głowie gdy chciałem tę samą funkcjonalność aplikacji zrobić bez EF. Wtedy pisałem sql recznie i miałem tylko select z punktu 1 a pozniej juz sam napisałem update, czyli robiąc ręcznie pomijam pkt 5.

4

Nie musisz, robisz coś tego typu

using (var ctx = new DatabaseContext())
{
    var person = new Person
    {
        Id = id,
        Name = "Tomek" // new name
    };

    ctx.Attach(person);
    ctx.Entry(person).Property(x => x.Name).IsModified = true;
    
    ctx.SaveChanges();
}

Tylko jak widzisz musisz mieć Id oraz nową nazwę, czyli tak samo jakbyś ręcznie klepał SQL.

0

Czyli ten sposób, który uzywałem jest nieprawidłowy i tak się nie powinno robić?

0

Totalnie nie znam się na EF i C#, ale trochę znam się na ORMach. To że robisz pobranie danych, modyfikację i save niekoniecznie znaczy że jest tam robiony select i ... i w zasadzie co jeszcze? Możliwe że jest tam z tego generownany jeden UPDATE na bazie. Musiałbyś włączyć opcję podglądu generowanych SQLi (o ile taka opcja jest). To wtedy byś dokładnie wiedział co tam EF sobie ogarnął

1

@kalimata:

Opisany przez ciebie sposób jest chyba najwygodniejszym, aczkolwiek jak zauważyłeś nie jest najwydajniejszym.

W podejściu z

ctx.Entry(person).Property(x => x.Name).IsModified = true;

jest ten problem, że musisz wiedzieć co się zmieniło lub zrobić diffa obiektów aby to odkryć np.

if (input.UserName != current.UserName)
{
    current.UserName = input.UserName;
    ctx.Entry(current).Property(x => x.UserName).IsModified = true;
}

ale pozwala ci to napisać wydajniej w/w query.

Jest jeszcze chyba jeden sposób, że zapisujesz starą encje w pamięci, robisz na niej później Attach i tylko nadpisujesz name i może nawet bez tego IsModified EF ogarnie, ale tu dochodzą ci różne problemy typu zapis wielu userów na raz, itd. Nie robiłem tak.

2

Nie wiem jak "genetycznie" EF umiejscowić.

Np Javowski JPA głęboko tkwi w czasach desktopu / EJB2, co powoduje że pobranie z bazy i UTZRYMYWANIE stanu obiektu - dokładnie wskazanej instancji obiektu - aż do końca miało głęboki sens.
To utraciło sens w czasach weba, zupełnie inna sesja bazodanowa pobiera i produkuje dane "DO" przeglądarki, a inna przyjmuje dane "OD", niekiedy nawet na innej maszynie (np jakieś formy load balansingu).

Więc w czasach weba koszty wzrosły *) - tak.

Ale żeby nie tylko krytykować.
Jak patrzę w przykład, gdzie operujesz imieniem / nazwiskiem, to realnym produkcyjnym programowania często są dane na tyle ważne, że zmiana jest odnotowana w innej tabeli historyczne itd...
Wiec realny programista realnego systemu np typu kadrowego by nie płakał, że musi pobrać encje tylko po to, aby ją zaraz zapisać. Więc nie byłby zbytnio zainteresowany, aby tylko i jedynie zaktualizować imię, dokładnie jednym sqlowym Update. W praktyce z ta encją by kazał np repozytorium zrobić jakiś złożony ślad.

Wiec zależy czy pytasz naprawdę o imię w systemie kadrowym, czy tylko taki przykład.

Optymalizowanie na skrajnie małą ilość zapisów sqlowych może utrudniać kierowalność kodu biznesowego, rzeczy stają się zbyt szczegółowe / dwoiste tu tak, tam inaczej - choc oczywiście można sobie zadać taki cel, i to w jakiś warunkach jest ze wszech miar ok.

*) nie tylko koszty, ale bardzo wzrósł nacisk na porządny locking, aby p Krysia i p. Basia w kadrach nie niszczyły sobie danych

0

@ZrobieDobrze: to tylko taki przykład z tym imieniem, żeby łatwo pokazać o co mi chodziło. Realnie pol do update'u będzie zapewne więcej i użytkownik może zmodyfikowac które chce a nie koniecznie tylko imie :)

0

@kalimata:

Znasz bliżej locking, a zwłaszcza optymistic locking ? Te jest scenariusz pracy taki, że drugie pobranie (przed zapisem aktualizacji) jest bardzo ważne. Więc nie zawsze warto "oszczędzać"

0
ZrobieDobrze napisał(a):

@kalimata:

Znasz bliżej locking, a zwłaszcza optymistic locking ? T...

Nie znam, muszę o tym poczytać. :)

3

No z tego co opisujesz to żeby zaktualizować potrzebujesz standardowo dwóch requestów.
Nie liczę tego pierwszego, który był po to, żeby wyświetlić dane :P

Typowo, robiłbym to tak jak opisałeś i nie bawił w cyrki z attachem i ręcznym oznaczaniem, które pola zostały zmodyfikowane. Szczególnie, że znowu w typowym API jak masz jakiś endpoint, który potrafi zaktualizować obiekt i przyjmuje ten obiekt w całości, to nie będzie tak łatwo określić, które pola zostały zmodyfikowane, a które nie.

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