Diciamo che hai queste classi nelle tue entità.
public class Parent
{
public int ParentID { get; set; }
public virtual ICollection<Child> Children { get; set; }
}
public class Child
{
public int ChildID { get; set; }
public int ParentID { get; set; }
public virtual Parent Parent { get; set; }
}
E hai un'interfaccia utente per aggiornare il Parent
insieme ai suoi Children
, nel senso che se l'utente aggiunge un nuovo Child
allora devi inserire, se l'utente modifica un Child
esistente, allora devi aggiornarlo e se l'utente rimuove un Child
allora tu devi cancellare. Ora ovviamente se si utilizza il seguente codice
public void Update(Parent obj)
{
_parent.Attach(obj);
_dbContext.Entry(obj).State = EntityState.Modified;
_dbContext.SaveChanges();
}
non sarà in grado di rilevare le modifiche all'interno del Child
perché EF non può rilevare le modifiche all'interno di una proprietà di navigazione.
Ho fatto questa domanda per tipo 4 volte e ottenere risposte miste. Quindi è davvero possibile fare questa roba senza che si complichi? Questo problema può risolvere il problema separando l'interfaccia utente tra Parent
e Child
ma non lo voglio perché l'unione di Child
e Parent
in un menu è piuttosto comune nello sviluppo di applicazioni aziendali e più user-friendly.
AGGIORNAMENTO: sto provando la soluzione qui sotto ma non funziona.
public ActionResult(ParentViewModel model)
{
var parentFromDB = context.Parent.Get(model.ParentID);
if (parentFromDB != null)
{
parentFromDB.Childs = model.Childs;
}
context.SaveChanges();
}
Invece di rilevare i cambiamenti all'interno dei bambini, EF non sarà in grado di dire cosa fare con il vecchio bambino. Ad esempio se parentFromDB
ha 3 figli la prima volta che lo estraggo dal DB, allora cancello il 2 ° e il 3 ° figlio. Quindi sto ottenendo The relationship could not be changed because one or more of the foreign-key properties is non-nullable
durante il salvataggio.
Credo che questo sia quello che è successo: la relazione non può essere cambiata perché una o più proprietà della chiave esterna non sono annullabili
Il che mi ha riportato al punto di partenza perché, nel mio scenario, non posso semplicemente recuperare dal DB e aggiornare la voce e chiamare SaveChanges
.
perché EF non è in grado di rilevare le modifiche all'interno della proprietà di navigazione
Questa sembra una descrizione un po 'distorta del fatto che _dbContext.Entry(obj).State = EntityState.Modified
non contrassegna le proprietà di navigazione come modificate.
Ovviamente EF tiene traccia delle modifiche nelle proprietà di navigazione. Tiene traccia delle modifiche nelle proprietà e nelle associazioni di tutte le entità collegate a un contesto. Pertanto, la risposta alla tua domanda, ora affermata positivamente ...
È possibile aggiornare la raccolta dei bambini in EF fuori dalla scatola
... è: sì .
L'unica cosa è: non lo fai fuori dalla scatola .
Il modo "out of the box" per aggiornare qualsiasi entità, che si tratti di un genitore o di un bambino in alcune raccolte è:
SaveChanges()
. È tutto. Ef tiene traccia delle modifiche e non avete mai insieme di entità State
in modo esplicito s.
Tuttavia, in uno scenario disconnessi (n-tier), questo diventa più complicato. Eseguiamo la serializzazione e la deserializzazione delle entità, quindi non ci può essere alcun contesto che tenga traccia delle loro modifiche. Se vogliamo archiviare le entità nel database, ora è nostro compito far conoscere a EF le modifiche. Ci sono fondamentalmente due modi per farlo:
Quando si tratta di associazioni, dobbiamo sempre dipingere lo stato . Dobbiamo ottenere le entità attuali dal database e determinare quali bambini sono stati aggiunti / cancellati. Non c'è modo di inferire questo dal grafico dell'oggetto deserializzato stesso.
Esistono vari modi per alleviare questo compito noioso ed elaborato di dipingere lo stato, ma questo va oltre lo scopo di questa sessione di domande e risposte. Alcuni riferimenti: