web-dev-qa-db-fra.com

La contrainte de multiplicité a été violée. Le rôle '...' de la relation '...' a une multiplicité de 1 ou 0..1

Je reçois l'erreur suivante de mon DbContext: "La contrainte de multiplicité a été violée. Le rôle 'MyEntity' de la relation 'MyModel.FK_ChildEntities_MyEntities' a la multiplicité 1 ou 0..1."

en utilisant ASP.NET, Entity Framework 4

Travailler avec une entité détachée 

L'erreur se produit la deuxième fois que j'essaie de rattacher une entité au dbcontext. Le scénario est une sauvegarde infructueuse suivie d'une nouvelle tentative. 

J'ai une entité détachée en session. L'utilisateur modifie les propriétés d'un formulaire, ajoute des éléments, supprime des éléments et clique sur Enregistrer. Je reçois une copie attachée de l'entité à partir d'une nouvelle instance de dbcontext, applique les modifications de l'entité détachée à l'entité attachée, valide, trouve une erreur et abandonne. L'utilisateur change ce qu'il veut et enregistre à nouveau. 

Lors de la deuxième sauvegarde, tout le processus de sauvegarde se répète, mais cette fois, tout se passe bien. Presque tout est dupliqué, ce qui cause une erreur ou une autre ou la totalité d'entre eux. Les valeurs des vues et des tables de recherche supposées être uniquement des références sont créées et de nouveaux identifiants. La plupart de ces problèmes que j'ai pu résoudre, mais il me reste l'erreur de multiplicité. Les éléments enfants sont créés en tant que copies exactes d'autres éléments enfants, jusqu'à l'identifiant unique, uniquement dans l'état Added. Ou, si je fais référence à certaines propriétés, au lieu de cloner un enfant non modifié, il supprime le nouveau. Quoi qu'il en soit, aucun code ne s'exécute comme il l'avait fait la première fois. 

Je supprime l'instance de dbcontext et l'entité attachée à chaque tentative de sauvegarde. Je pensais que cela suffirait pour annuler tout changement, mais il doit rester quelque chose. La seule chose qui n’a pas été repérée ou réinitialisée est l’entité détachée, qui est en session, mais je n’y apporte aucune modification. Du moins pas directement.

Le code (très simplifié) ressemble à ceci:

void Save()
{
using (var context = new MyContext())
{
   // detached entity from session
   MyEntity detachedEntity = (MyEntity)Session["DetachedEntity"];

   // attached entity from context
   MyEntity attachedEntity = context.MyEntities.Single(x=>x.id == detachedEntity.id);       


   // <remove children representing lookup table elements from detachedEntity to prevent duplicates>
   // <remove children representing view elements from detachedEntity to prevent duplicates>


   // <apply changes from detachedEntity to attachedEntity>


   // <add new children>
   // <remove deleted children>
   // <update modified children>


   // <set entity state to unchanged on view and lookup elements of attachedEntity to ensure no duplicates...>


   // <validate>


   if (errors.count>0)
     // <report errors>
   else
     context.SaveChanges();
}
}

à titre d'exemple, cela génère une erreur de multiplicité:

// represents first save:
    using (var context = new MyContext())
    {
       // detached entity from session
       MyEntity detachedEntity = (MyEntity)Session["DetachedEntity"];

       // attached entity from context
       MyEntity attachedEntity = context.MyEntities.Single(x=>x.id == detachedEntity.id);       

       int debug1 = context.ChangeTracker.Entries<ChildEntity>().Count(); // debug1 == 0;

       attachedEntity.ChildEntities.Add(detachedEntity.ChildEntities.First());

       int debug2 = context.ChangeTracker.Entries<ChildEntity>().Count(); // debug2 == 1;

    }

// represents second save:
    using (var context = new MyContext())
    {
       // detached entity from session
       MyEntity detachedEntity = (MyEntity)Session["DetachedEntity"];

       // attached entity from context
       MyEntity attachedEntity = context.MyEntities.Single(x=>x.id == detachedEntity.id);    

       int debug1 = context.ChangeTracker.Entries<ChildEntity>().Count(); // debug1 == 0;

       attachedEntity.ChildEntities.Add(detachedEntity.ChildEntities.First());

       int debug2 = context.ChangeTracker.Entries<ChildEntity>().Count(); // multiplicity error;

    }
12
user1566694

d'une manière ou d'une autre, dbcontext se souvient des objets qui y ont été ajoutés. si le même objet apparaît deux fois, il ... souffle

au lieu d'ajouter des entités enfants de mon entité détachée à celles attachées, j'aurais dû créer de nouvelles copies de chaque enfant

ChildEntity detachedChild = detachedEntity.ChildEntities.First();
attachedEntity.ChildEntities.Add(new ChildEntity { 
   propertyA = detachedChild.propertyA,
   propertyB = detachedChild.propertyB
});

au lieu de 

attachedEntity.ChildEntities.Add(detachedEntity.ChildEntities.First());
15
user1566694

Le problème est que détachéeChild.parent doit être assignée joinParent.

foreach(var detachedEntity in detachedEntities)
{
     attachedEntity.ChildEntities.Add(detachedEntity); 
     detachedEntity.ParentEntity = attachedEntity;
}
6
Arturo Hernandez

Assurez-vous d'inspecter les propriétés de l'objet que vous essayez d'ajouter. Dans mon cas, il s'agissait à tort de référencer le même objet non valide sur chaque ajout qui ne lui plaisait pas et a donc lancé la même erreur que vous avez ici.

1
bbodenmiller

J'ai rencontré cette erreur lorsque j'avais des propriétés de navigation non définies ou des propriétés de navigation appartenant au code incorrect First DBContext

0
Kirsten Greed

J'ai résolu ce problème en rendant les collections enfants de l'entité parent virtuelle. Cela permet de mettre facilement à jour l'entité lorsque ses collections enfants ne changent pas, ce qui était pour moi la plupart du temps.

0
user1040323

EF 6 Update

Pour moi, régler l’état de l’objet sur ajouté a fonctionné sur des sons

ChildEntity detachedChild = detachedEntity.ChildEntities.First();
var newChild = new ChildEntity { 
   propertyA = detachedChild.propertyA,
   propertyB = detachedChild.propertyB
});

// Mark all added entity entity state to Added
 attachedEntity.ChildEntities.Add(newChild );
                        db.Entry(newChild ).State = EntityState.Added;

http://www.entityframeworktutorial.net/EntityFramework4.3/update-one-to-many-entity-using-dbcontext.aspx

0
Anshul Nigam