Come faccio a modificare un'entità utilizzando l'Entity Framework Codice Primo approccio?
-
09-10-2019 - |
Domanda
Sono stato strappando i capelli fuori sopra questo per giorni e prima di andare completamente calvo è il momento di chiedere a tutte le persone più intelligenti di me come fare questo.
Sto utilizzando Entity Framework 4 del Codice primo CTP 5 e MVC 3.
Il messaggio di eccezione in questo momento è "Un oggetto con la stessa chiave esiste già nella ObjectStateManager. L'ObjectStateManager non può monitorare più oggetti con la stessa chiave."
In primo luogo qui è il controller del modulo di modifica viene inviato a:
public ActionResult Save(ClientEntity postedClient)
{
try
{
if (ModelState.IsValid)
{
Base.clientInterface.Save(postedClient);
return RedirectToAction("Index");
}
}
catch (Exception)
{
throw;
}
SetupManageData(null, postedClient);
return View("Manage");
}
Il metodo Save sull'interfaccia del client è questa:
public void Save(ClientEntity theClient)
{
SetContext();
if (theClient.clientId == 0)
this.pContext.Clients.Add(theClient);
else
{
ClientEntity existingClient = GetSingle(theClient.clientId); // Get the existing entity from the data store.
// PseudoCode: Merge existingClient and theClient - Can this be done without using ObjectStateManager?
// PseudoCode: Attach merged entity to context so that SaveChanges will update it in the database - is this correct?
}
this.pContext.SaveChanges();
}
private void SetContext()
{
if (this.pContext == null)
this.pContext = new PersistanceContext();
}
contesto Persistenza è il DbContext e si presenta così:
public class PersistanceContext : DbContext
{
public DbSet<ClientEntity> Clients { get; set; }
}
Soluzione
Qual è lo stile di vita di clientInterface? si tratta di un singolo o di qualcosa che tiene in vita attraverso più richieste?
La mia ipotesi è che abbia un esempio vivo di un contesto di database che è stato utilizzato per andare a prendere l'entità della richiesta GET e quando il POST cerca di (ri) aggiungere un'entità client al contesto, il vecchio è ancora lì e sono in conflitto.
Prova distruggere l'oggetto che si trova dietro il clientInterface con ogni richiesta. Forse utilizzare un contenitore DI supportati per-WebRequest stili di vita in modo da non devono preoccuparsi.
Spero che la mia ipotesi era giusta e questo è di aiuto.
Altri suggerimenti
Questo dovrebbe funzionare.
if (theClient.clientId == 0)
{
this.pContext.Clients.Add(theClient);
}
else
{
ClientEntity existingClient = this.pContext.Clients.Single(o => o.ClientId == theClient.ClientId);
// map properties
existingClient.Name = theClient.name;
// ....
}
this.pContext.SaveChanges();
[Modifica]
E 'più facile (IMHO) per dividere la creazione e la modifica di oggetti in 2 viste separate e per evitare la mappatura delle proprietà che uso TryUpdateModel.
[HttpPost]
public ViewResult Edit(int clientID, FormCollection collection)
{
var client = pContext.Clients.SingleOrDefault(o => o.ID == clientID);
if(!TryUpdateModel(client, collection))
{
ViewBag.UpdateError = "Update Failure";
}
else
{
db.SubmitChanges();
}
return View("Details", client);
}
[HttpPost]
public ViewResult Create(FormCollection collection)
{
var client = new Client();
if(!TryUpdateModel(client, collection))
{
ViewBag.UpdateError = "Create Failure";
}
else
{
db.Clients.Add(client);
db.SubmitChanges();
}
return View("Details", client);
}