Plusieurs entités ajoutées peuvent avoir la même clé primaire

Voici mon modèle de 3 entités: Route, Location et LocationInRoute.
modèle

la méthode suivante échoue et obtient une exception lorsqu’elle est validée:

public static Route InsertRouteIfNotExists(Guid companyId, IListLocation> locations) { //Loop on locations and insert it without commit InsertLocations(companyId, routesOrLocations); RouteRepository routeRep = new RouteRepository(); Route route = routeRep.FindRoute(companyId, locations); if (route == null) { route = new Route() { CompanyId = companyId, IsDeleted = false }; routeRep.Insert(route); LocationInRouteRepository locInRouteRep = new LocationInRouteRepository(); for (int i = 0; i < locations.Count; i++) { locInRouteRep.Insert(new LocationInRoute() { //Id = i, LocationId = locations[i].Id, Order = i, RouteId = route.Id }); } } return route; } 

En faisant:

 InsertRouteIfNotExists(companyId, locations); UnitOfWork.Commit(); 

J’ai eu:

Impossible de déterminer la fin principale de la relation ‘SimTaskModel.FK_T_STF_SUB_LOCATION_IN_ROUTE_T_STF_LOCATION_location_id’. Plusieurs entités ajoutées peuvent avoir la même clé primaire.

Lorsque vous divisez le commit et insérez-le dans les mesures, cela fonctionne:

  public static Route InsertRouteIfNotExists(Guid companyId, IListLocation> locations) { //Loop on locations and insert it without commit InsertLocations(companyId, routesOrLocations); UnitOfWork.Commit(); RouteRepository routeRep = new RouteRepository(); Route route = routeRep.FindRoute(companyId, locations); if (route == null) { route = new Route() { CompanyId = companyId, IsDeleted = false }; routeRep.Insert(route); LocationInRouteRepository locInRouteRep = new LocationInRouteRepository(); for (int i = 0; i < locations.Count; i++) { locInRouteRep.Insert(new LocationInRoute() { //Id = i, LocationId = locations[i].Id, Order = i, RouteId = route.Id }); } UnitOfWork.Commit(); } return route; } 

Je voudrais appeler commit une fois et en dehors de la méthode. Pourquoi cela échoue dans le premier exemple et que signifie cette exception?

L’erreur est causée par un identifiant de clé étrangère (par opposition à une référence) qui ne peut pas être résolu. Dans votre cas, vous avez un LocationInRole qui référence un emplacement avec un ID de 0. Il existe plusieurs emplacements avec cet ID.

Un ID n’a pas encore été atsortingbué aux emplacements car ils n’ont pas encore été enregistrés dans la firebase database, c’est-à-dire lorsque l’ID est généré. Dans votre deuxième exemple, les emplacements sont enregistrés avant que leurs identifiants ne soient accessibles, ce qui explique pourquoi cela fonctionne.

Vous ne pourrez pas vous fier aux ID d’emplacement pour définir les relations si vous souhaitez enregistrer uniquement les modifications ultérieures.

Changez la ligne suivante …

 LocationId = locations[i].Id 

…pour ça…

 Location = locations[i] 

Les relations seront alors basées sur des références d’object qui ne dépendent pas des ID de localisation.

Dans le cas où cela serait utile aux futurs lecteurs, dans mon cas, cette erreur était due à une clé étrangère mal configurée dans ma firebase database (et au modèle généré à partir de la firebase database).

J’avais des tables:

 Parent (1-1) Child (1-many) Grandchild 

et la table des petits-enfants avait reçu par inadvertance une clé étrangère jusqu’à son parent (enfant) et son grand-parent (parent). En enregistrant plusieurs entités parents à partir de nouvelles, j’ai reçu cette erreur. Le correctif a été de corriger la clé étrangère.

Ayant rencontré la même erreur, je soupçonne fortement que le problème réel était la définition de l’emplacement. En termes simples, dans EF Code First, je parie que cela ressemblait à ceci:

 public class Location { public int Id { get; set; } ... public Location ParentLocation { get; set; } [ForeignKey("ParentLocation")] public int ParentLocationId { get; set; } } 

En d’autres termes, dans la question, ParentLocation / ParentLocationId est une référence récursive à cette table.

Le ParentLocationId n’est pas Nullable. Cela signifie qu’il va être inséré avec un 0, et EF va se plaindre sur Insert, plutôt que lorsque vous migrez – même si la vérité est une fois que Migration s’exécute, vous avez une table EF ne vous laissera jamais insérer dans.

La seule façon de faire une référence récursive à la même table est de rendre la référence récursive nullable:

 public class Location { public int Id { get; set; } ... public Location ParentLocation { get; set; } [ForeignKey("ParentLocation")] public int? ParentLocationId { get; set; } } 

Notez le ? après l’ int .

Pour ceux qui recherchent cette exception:
Dans mon cas, il était impossible de définir une propriété de navigation requirejse.

 public class Question { //... public int QuestionGridItemID { get; set; } public virtual QuestionGridItem GridItem { get; set; } //... public int? OtherQuestionID { get; set; } public Question OtherQuestion { get; set; } } //... question.OtherQuestion = otherQuestion; questionGridItem.Questions.Add(question); dataContext.SaveChanges(); //fails because otherQuestion wasn't added to //any grid item's Question collection 

J’ai eu le même problème. avec le scénario ci-dessous résolu pour moi. Je pense que vous devez changer votre code comme ci-dessous:

 var insertedRoute =routeRep.Insert(route); ..... insertedRoute.LocationInRoute = new List(); for(....){ var lInRoute = new LocationInRoute(){ .... Route=insertedRoute; } insertedRoute.LocationInRoute.Add(lInRoute ); }