Clé déjà existante dans EF.ObjectStateManager
2013-09-03 #ef#unit-test
En ce moment, je testunite beaucoup et comme je persiste à utiliser une base de données SQL CE pour ce qui touche à Entity Framework, je cherche tous les moyens possibles pour améliorer la vitesse de mes tests.
Suite à ma dernière optimisation, j'avait 2 tests unitaires qui ne passaient plus.
Un objet ayant la même clé existe déjà dans ObjectStateManager. ObjectStateManager ne peut pas assurer le suivi de plusieurs objets ayant la même clé.
Ou en anglais :
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
Dans les 2 tests, il s'agissait de vérifier que le POST sur l'action "Edit" d'un contrôleur redirigeait bien vers l'action "Details" en cas de succès.
//
// POST: /Theaters/Edit/5
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Edit(Theater theater)
{
if (ModelState.IsValid)
{
// Enregistre les modifications
var place = db.Places.Find(theater.Place_ID);
theater.KeyTheater = StringHelper.Slugify(place.Caption + " " + theater.ShortName);
db.Entry(theater).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Details", new { id = theater.Theater_ID });
}
ViewBag.Place_ID = db.SelectListPlaces(this.Department_ID, theater.Place_ID);
return View(theater);
}
L'erreur apparaissait pile sur la ligne db.Entry(theater).State = EntityState.Modified;
.
Dans tous les autres contrôleurs, le problème ne se présentait pas, mais
uniquement dans ces 2 cas là. Après quelques recherches, il semblerait que le
fait d'utiliser l'objet theater
dans la ligne var place = db.Places.Find(theater.Place_ID);
soit suffisant pour que l'entité soit
référencée dans l'ObjectStateManager
de Entity Framework.
Et ensuite, la commande db.Entry(theater).State = EntityState.Modified;
provoquait à nouveau son référencement alors qu'il
l'avait déjà été deux lignes plus tôt (mais ça EF ne semblait pas capable de
s'en rendre compte).
J'ai trouvé plusieurs trucs sur internet pour éviter le problème, mais quant à moi, j'ai préféré tout simplement marquer l'objet à l'état "Modified" avant de l'utiliser pour retrouver la commune correspondante :
// Enregistre les modifications
db.Entry(theater).State = EntityState.Modified;
var place = db.Places.Find(theater.Place_ID);
theater.KeyTheater = StringHelper.Slugify(place.Caption + " " + theater.ShortName);
db.SaveChanges();