Te dwie jednostki są relacjami jeden-do-wielu (zbudowane przez kod pierwszy fluent API).
public class Parent
{
public Parent()
{
this.Children = new List<Child>();
}
public int Id { get; set; }
public virtual ICollection<Child> Children { get; set; }
}
public class Child
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Data { get; set; }
}
W moim kontrolerze WebApi mam akcje, aby utworzyć podmiot nadrzędny (który działa dobrze) i zaktualizować podmiot nadrzędny (który ma jakiś problem). Akcja aktualizacji wygląda następująco:
public void Update(UpdateParentModel model)
{
//what should be done here?
}
Obecnie mam dwa pomysły:
Uzyskaj śledzoną jednostkę nadrzędną o nazwie
existing
przezmodel.Id
i przypisz wartościmodel
po kolei do encji. To brzmi głupio. Imodel.Children
nie wiem, które dziecko jest nowe, które jest modyfikowane (a nawet usuwane).Utwórz nową jednostkę nadrzędną za pośrednictwem
model
i dołącz ją do DbContext i zapisz. Ale w jaki sposób DbContext może poznać stan elementów podrzędnych (nowe dodawanie / usuwanie / modyfikowanie)?
Jaki jest prawidłowy sposób zaimplementowania tej funkcji?
źródło
Odpowiedzi:
Ponieważ model, który jest wysyłany do kontrolera WebApi, jest odłączany od dowolnego kontekstu platformy encji (EF), jedyną opcją jest załadowanie wykresu obiektu (nadrzędnego, w tym jego dzieci) z bazy danych i porównanie, które elementy podrzędne zostały dodane, usunięte lub zaktualizowany. (Chyba że śledziłbyś zmiany własnym mechanizmem śledzenia w stanie odłączonym (w przeglądarce lub gdziekolwiek), który moim zdaniem jest bardziej złożony niż następujący.) Mogłoby to wyglądać tak:
...CurrentValues.SetValues
może przyjmować dowolny obiekt i mapuje wartości właściwości do dołączonej jednostki na podstawie nazwy właściwości. Jeśli nazwy właściwości w modelu różnią się od nazw w encji, nie możesz użyć tej metody i musisz przypisać wartości pojedynczo.źródło
existingParent.Children.Add(newChild)
ponieważ wówczas wyszukiwanie istniejącego linqChild zwróci ostatnio dodaną jednostkę, a więc ta jednostka zostanie zaktualizowana. Wystarczy wstawić do tymczasowej listy, a następnie dodać.existingChild
zapytaniu LINQ:.Where(c => c.ID == childModel.ID && c.ID != default(int))
Bawiłem się czymś takim ...
do którego możesz zadzwonić za pomocą czegoś takiego:
Niestety, ten rodzaj przewraca się, jeśli istnieją właściwości kolekcji w typie podrzędnym, które również wymagają aktualizacji. Rozważ próbę rozwiązania tego problemu przez przekazanie IRepository (z podstawowymi metodami CRUD), które byłoby odpowiedzialne za samodzielne wywołanie UpdateChildCollection. Wywołałby repozytorium zamiast bezpośrednich wywołań DbContext.Entry.
Nie mam pojęcia, jak to wszystko będzie działać na dużą skalę, ale nie wiem, co jeszcze zrobić z tym problemem.
źródło
toAdd.ForEach(i => (selector(dbItem) as ICollection<Tchild>).Add(i.Value));
powinien rozwiązać problem n -> n.W porzadku chlopaki. Miałem tę odpowiedź raz, ale zgubiłem ją po drodze. absolutna tortura, kiedy wiesz, że jest lepszy sposób, ale nie możesz go sobie przypomnieć ani znaleźć! To jest bardzo proste. Właśnie przetestowałem to na wiele sposobów.
Możesz zastąpić całą listę nową! Kod SQL usunie i doda jednostki w razie potrzeby. Nie musisz się tym przejmować. Pamiętaj, aby dołączyć kolekcję podrzędną lub nie mieć kości. Powodzenia!
źródło
Jeśli używasz EntityFrameworkCore, możesz wykonać następujące czynności w akcji post kontrolera ( metoda Attach rekursywnie dołącza właściwości nawigacji, w tym kolekcje):
Zakłada się, że każda zaktualizowana jednostka ma wszystkie właściwości ustawione i podane w danych postu od klienta (np. Nie będzie działać przy częściowej aktualizacji jednostki).
Musisz również upewnić się, że do tej operacji używasz nowego / dedykowanego kontekstu bazy danych platformy jednostki.
źródło
W ten sposób rozwiązałem ten problem. W ten sposób EF wie, które dodać, które zaktualizować.
źródło
Istnieje kilka projektów, które ułatwiają interakcję między klientem a serwerem, jeśli chodzi o zapisywanie całego grafu obiektu.
Oto dwa, na które chciałbyś spojrzeć:
Oba powyższe projekty rozpoznają odłączone jednostki po ich zwróceniu na serwer, wykrywają i zapisują zmiany oraz zwracają dane klienta.
źródło
Samo potwierdzenie koncepcji
Controler.UpdateModel
nie będzie działać poprawnie.Pełna klasa tutaj :
źródło
@Charles McIntosh naprawdę dał mi odpowiedź na moją sytuację, ponieważ przekazany model został odłączony. Dla mnie to, co ostatecznie zadziałało, to najpierw zapisanie przekazanego modelu ... a następnie kontynuowanie dodawania dzieci, tak jak byłem wcześniej:
źródło
Dla programistów VB.NET Użyj tego ogólnego sub do oznaczenia stanu podrzędnego, łatwego w użyciu
źródło
źródło
źródło
Oto mój kod, który działa dobrze.
źródło