En un mot, l'exception est levée lors du POSTing du modèle de wrapper et en changeant l'état d'une entrée en «Modifié». Avant de changer l'état, l'état est défini sur «Détaché» mais l'appel de Attach () renvoie la même erreur. J'utilise EF6.
Veuillez trouver mon code ci-dessous (les noms des modèles ont été modifiés pour le rendre plus facile à lire)
Modèle
// Wrapper classes
public class AViewModel
{
public A a { get; set; }
public List<B> b { get; set; }
public C c { get; set; }
}
Manette
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
if (!canUserAccessA(id.Value))
return new HttpStatusCodeResult(HttpStatusCode.Forbidden);
var aViewModel = new AViewModel();
aViewModel.A = db.As.Find(id);
if (aViewModel.Receipt == null)
{
return HttpNotFound();
}
aViewModel.b = db.Bs.Where(x => x.aID == id.Value).ToList();
aViewModel.Vendor = db.Cs.Where(x => x.cID == aViewModel.a.cID).FirstOrDefault();
return View(aViewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(AViewModel aViewModel)
{
if (!canUserAccessA(aViewModel.a.aID) || aViewModel.a.UserID != WebSecurity.GetUserId(User.Identity.Name))
return new HttpStatusCodeResult(HttpStatusCode.Forbidden);
if (ModelState.IsValid)
{
db.Entry(aViewModel.a).State = EntityState.Modified; //THIS IS WHERE THE ERROR IS BEING THROWN
db.SaveChanges();
return RedirectToAction("Index");
}
return View(aViewModel);
}
Comme indiqué ci-dessus la ligne
db.Entry(aViewModel.a).State = EntityState.Modified;
lève une exception:
L'association d'une entité de type «A» a échoué car une autre entité du même type a déjà la même valeur de clé primaire. Cela peut se produire lorsque vous utilisez la méthode «Attacher» ou que vous définissez l'état d'une entité sur «Inchangé» ou «Modifié» si des entités du graphique ont des valeurs de clé en conflit. Cela peut être dû au fait que certaines entités sont nouvelles et n'ont pas encore reçu de valeurs de clé générées par la base de données. Dans ce cas, utilisez la méthode «Ajouter» ou l'état d'entité «Ajouté» pour suivre le graphique, puis définissez l'état des entités non nouvelles sur «Inchangé» ou «Modifié» selon le cas.
Est-ce que quelqu'un voit quelque chose de mal dans mon code ou comprend dans quelles circonstances cela générerait une telle erreur lors de l'édition d'un modèle?
la source
EntityState
? Comme votre entité provient d'une demande de publication, elle ne doit pas être suivie par le contexte actuel, je suppose qu'elle considère que vous essayez d'ajouter un élément avec un identifiant existantdb
instance est la même entre vos deux actions, elle peut expliquer votre problème, car votre élément est chargé par la méthode GET (puis suivi par le contexte), et il se peut qu'il ne reconnaisse pas celui de votre méthode POST comme l'entité récupérée auparavant .canUserAccessA()
Charge- elle l'entité directement ou en tant que relation d'une autre entité?Réponses:
Problème résolu!
Attach
La méthode pourrait potentiellement aider quelqu'un, mais cela n'aiderait pas dans cette situation car le document était déjà en cours de suivi lors de son chargement dans la fonction de contrôleur Edit GET. Attach générerait exactement la même erreur.Le problème que je rencontre ici a été causé par la fonction
canUserAccessA()
qui charge l'entité A avant de mettre à jour l'état de l'objet a. Cela foutait en l'air l'entité suivie et cela changeait l'état d'un objet enDetached
.La solution était de modifier
canUserAccessA()
pour que l'objet que je chargeais ne soit pas suivi. La fonctionAsNoTracking()
doit être appelée lors de l'interrogation du contexte.Pour une raison quelconque, je ne pourrais pas utiliser
.Find(aID)
avecAsNoTracking()
mais cela n'a pas vraiment d'importance car je pourrais obtenir la même chose en modifiant la requête.J'espère que cela aidera quiconque ayant un problème similaire!
la source
using System.Data.Entity;
utiliserAsNoTracking()
.De façon intéressante:
Ou si vous n'êtes toujours pas générique:
semble résoudre mon problème en douceur.
la source
AddOrUpdate
est une méthode d'extension dans l'System.Data.Entity.Migrations
espace de noms.Il semble que l'entité que vous essayez de modifier n'est pas correctement suivie et n'est donc pas reconnue comme modifiée, mais ajoutée à la place.
Au lieu de définir directement l'état, essayez de faire ce qui suit:
De plus, je voudrais vous avertir que votre code contient une vulnérabilité de sécurité potentielle. Si vous utilisez une entité directement dans votre modèle de vue, vous risquez que quelqu'un modifie le contenu de l'entité en ajoutant des champs correctement nommés dans le formulaire soumis. Par exemple, si l'utilisateur ajoutait une zone de saisie avec le nom "A.FirstName" et que l'entité contenait ce champ, la valeur serait liée à viewmodel et enregistrée dans la base de données même si l'utilisateur ne serait pas autorisé à modifier cela dans le fonctionnement normal de l'application .
Mettre à jour:
Pour surmonter la vulnérabilité de sécurité mentionnée précédemment, vous ne devez jamais exposer votre modèle de domaine en tant que modèle de vue, mais utiliser plutôt un modèle de vue distinct. Ensuite, votre action recevrait viewmodel que vous pourriez mapper au modèle de domaine à l'aide d'un outil de cartographie comme AutoMapper. Cela vous empêcherait de modifier des données sensibles par l'utilisateur.
Voici une explication détaillée:
http://www.stevefenton.co.uk/Content/Blog/Date/201303/Blog/Why-You-Never-Expose-Your-Domain-Model-As-Your-MVC-Model/
la source
Essaye ça:
la source
pour moi, la copie locale était la source du problème. cela l'a résolu
la source
Mon cas était que je n'avais pas d'accès direct au contexte EF à partir de mon application MVC.
Donc, si vous utilisez une sorte de référentiel pour la persistance des entités, il pourrait être approprié de simplement détacher l'entité explicitement chargée, puis de définir EntityState lié sur Modified.
Exemple de code (abstrait):
MVC
Dépôt
la source
J'ai pensé partager mon expérience sur celui-ci, même si je me sens un peu idiot de ne pas m'en être rendu compte plus tôt.
J'utilise le modèle de référentiel avec les instances de repo injectées dans mes contrôleurs. Les référentiels concrets instancient mon ModelContext (DbContext) qui dure toute la durée de vie du référentiel, qui est
IDisposable
et éliminé par le contrôleur.Le problème pour moi était que j'avais un tampon et une version de ligne modifiés sur mes entités, donc je les recevais en premier afin de les comparer avec les en-têtes entrants. Bien sûr, cela chargeait et suivait l'entité qui était par la suite mise à jour.
Le correctif consistait simplement à changer le référentiel de la création d'un contexte une fois dans le constructeur à l'utilisation des méthodes suivantes:
Cela permet aux méthodes du référentiel de renouveler leur instance de contexte à chaque utilisation en appelant
GetDbContext
, ou d'utiliser une instance précédente si elles le souhaitent en spécifiant true.la source
J'ai ajouté cette réponse uniquement parce que le problème est expliqué sur la base de modèles de données plus complexes et que j'ai eu du mal à comprendre ici.
J'ai créé une application assez simple. Cette erreur s'est produite dans l'action Edit POST. L'action a accepté ViewModel comme paramètre d'entrée. La raison d'utiliser le ViewModel était de faire un calcul avant que l'enregistrement ne soit sauvegardé.
Une fois l'action passée par la validation telle que
if(ModelState.IsValid)
, mon acte répréhensible a été de projeter des valeurs de ViewModel dans une instance complètement nouvelle d'Entity. Je pensais que je devrais créer une nouvelle instance pour stocker les données mises à jour, puis enregistrer cette instance.Ce que j'avais réalisé plus tard, c'était que je devais lire l'enregistrement à partir de la base de données:
et mis à jour cet objet. Tout fonctionne maintenant.
la source
J'ai eu ce problème avec le var local et je le détache simplement comme ceci:
Les causes du problème des objets chargés avec la même clé, nous allons donc d'abord détacher cet objet et faire la mise à jour pour éviter les conflits entre deux objets avec la même clé
la source
J'ai eu un problème similaire, après avoir sondé pendant 2-3 jours, ".AsNoTracking" devrait être supprimé car EF ne suit pas les modifications et suppose qu'il n'y a pas de modifications à moins qu'un objet ne soit attaché. De plus, si nous n'utilisons pas .AsNoTracking, EF sait automatiquement quel objet enregistrer / mettre à jour, il n'est donc pas nécessaire d'utiliser Attach / Added.
la source
Utilisez
AsNoTracking()
là où vous obtenez votre requête.la source
J'ai rencontré cette erreur où
J'ai changé la méthode B pour avoir une instruction using et me fier uniquement au db2 local . Après:
la source
Semblable à ce que dit Luke Puplett, le problème peut être causé par une mauvaise suppression ou création de votre contexte.
Dans mon cas, j'avais une classe qui acceptait un contexte appelé
ContextService
:Mon service de contexte avait une fonction qui met à jour une entité à l'aide d'un objet entité instancié:
Tout cela allait bien, mon contrôleur où j'ai initialisé le service était le problème. Ma manette ressemblait à l'origine à ceci:
Je l'ai changé en ceci et l'erreur a disparu:
la source
Ce problème peut également être vu pendant
ViewModel
leEntityModel
mappage (en utilisantAutoMapper
, etc.) et en essayant d'inclurecontext.Entry().State
etcontext.SaveChanges()
un tel bloc d'utilisation comme indiqué ci-dessous résoudrait le problème. Veuillez garder à l'esprit que lacontext.SaveChanges()
méthode est utilisée deux fois au lieu d'utiliser juste après,if-block
car elle doit l'être également avec block.J'espère que cela t'aides...
la source
Voici ce que j'ai fait dans le cas similaire.
Cette situation signifie que la même entité a déjà existé dans le contexte.
Vérifiez d'abord depuis ChangeTracker si l'entité est dans le contexte
S'il existe
la source
Je parviens à résoudre le problème en mettant à jour l'état. lorsque vous déclenchez la recherche ou toute autre opération de requête sur le même état d'enregistrement a été mis à jour avec modifié, nous devons donc définir le statut sur Détaché, vous pouvez déclencher votre modification de mise à jour
la source
Je résous ce problème avec un bloc "using"
Voici où j'ai l'idée https://social.msdn.microsoft.com/Forums/sqlserver/es-ES/b4b350ba-b0d5-464d-8656-8c117d55b2af/problema-al-modificar-en-entity-framework?forum = vcses est en espagnol (cherchez la deuxième réponse)
la source
vous pouvez utiliser une méthode supplémentaire comme;
mais dans de nombreux cas, si vous souhaitez utiliser plus d'un modèle à ce moment-là, cela ne fonctionnera pas car l'entité est déjà attachée à une autre entité. Ainsi, à ce moment-là, vous pouvez utiliser la méthode ADDOrUpdate Entity Migration qui migre simplement l'objet de l'un à l'autre et, par conséquent, vous n'obtiendrez aucune erreur.
la source
Effacer tout l'état
dbContextGlobalERP.ChangeTracker.Entries (). Where (e => e.Entity! = null) .ToList (). ForEach (e => e.State = EntityState.Detached);
la source