Sto leggendo il seguente tutorial su Entity Framework 6 Link . E all'interno della sezione denominata "Aggiunta di una pagina di modifica per istruttori", l'autore ha scritto il seguente codice all'interno del metodo di azione Modifica post: -
[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public ActionResult EditPost(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var instructorToUpdate = db.Instructors
.Include(i => i.OfficeAssignment)
.Where(i => i.ID == id)
.Single();
if (TryUpdateModel(instructorToUpdate, "",
new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
{
try
{
if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
{
instructorToUpdate.OfficeAssignment = null;
}
db.Entry(instructorToUpdate).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
catch (RetryLimitExceededException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
}
return View(instructorToUpdate);
}
Questo codice coprirà queste tre condizioni:
Quindi significa questo
db.Entry(instructorToUpdate).State = EntityState.Modified;
causerà un'istruzione di inserimento da eseguire per il record OfficeAssignment in caso l'Istruttore non avesse un oggetto OfficeAssignment precedente? e qual è la regola che governa questo?
ecco lo schema del modello completo: -
DbContext.Entry
metodo DbContext.Entry
viene utilizzato per eseguire un caricamento esplicito , ovvero consente di accedere a tutte le informazioni che DbContext ha su un'entità. Questo va oltre i valori che sono memorizzati nelle proprietà dell'entità reale e include cose come lo stato dell'entità e i valori originali per ogni proprietà quando è stata recuperata dal database.
Quando si chiama il metodo TryUpdateModel
, aggiornerà le proprietà (che si passano i loro nomi come parametro) con valori dal raccoglitore del modello. Una di queste proprietà è OfficeAssignment
, anch'essa aggiornata. Se nella tua vista non entri in una Location
, non hai motivo di creare un nuovo OfficeAssigment
(è necessario che tu faccia instructorToUpdate.OfficeAssignment = null;
perché anche quando non inserisci una nuova Location
, avrà un'istanza di OfficeAssignment
). Se aggiungi una nuova Location
, creerai un nuovo OfficeAssignment
e, se hai modificato la Location
, allora ne OfficeAssignment
il valore. Quando lo fai:
db.Entry(instructorToUpdate).State = EntityState.Modified;
Stai per impostare un flag sull'entità che indica che è stato modificato. Quando viene chiamato il metodo SaveChanges
, il flag Modified
fa in modo che Entity Framework crei istruzioni SQL per aggiornare la riga del database. Tutte le colonne della riga del database verranno aggiornate, incluse quelle che l'utente non ha modificato e i conflitti di concorrenza vengono ignorati. Per capire meglio cosa happend, si può guardare l' Instructor
istanza come un albero. Code First riconosce che hai una proprietà di navigazione, quindi deve essere aggiornata o inserita (a seconda dei casi). Se OfficeAssignment
ha un Id
diverso da quello default(int)
(sto pressando che è un interger), allora verrà aggiornato e, in altri casi, verrà inserito.
Esistono fondamentalmente due modi in cui un'entità può essere mantenuta tramite EF.
A. Aggiungilo direttamente a Dbset con le relazioni aggiuntive che vuoi che abbia.
Entity e = new Entity();
e.ForeignEntityId = 123;
context.Entities.Add(e);
context.SaveChanges();
B. Collegalo a un'entità esistente e se tale entità è / non è stata tracciata, contrassegna tale entità come Modificata.
Entity e = new Entity();
ForeignEntity fe = context.Find(...);
//Only needed if 'fe' was untracked
//context.Entry(fe).State = EntityState.Modified;
fe.Entity = e;
context.SaveChanges();
La via presentata nella tua domanda è il secondo modo. Si tratta di ottenere che l'oggetto "nuovo" sia presente nel grafico dell'oggetto che rappresenta tutte le entità EF tracciate dal DB.