Plusieurs entités ajoutées peuvent avoir la même clé primaire
Voici mon modèle de 3 entités: Route, Location et LocationInRoute.
La méthode suivante échoue et obtient une exception lors de la validation:
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:
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.
Lors de la division du commit et insert in dans le methos - ça marche:
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?
5 réponses
L'erreur est causée par un ID 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 fait référence à un emplacement avec un ID de 0. Il y a plusieurs emplacements avec cet ID.
Les Emplacements n'ont pas encore reçu D'ID car ils n'ont pas encore été enregistrés dans la base de données qui est lorsque l'ID est généré. Dans votre deuxième exemple, les emplacements sont enregistrés avant l'accès à leurs identifiants, ce qui explique pourquoi cela fonctionne.
Vous allez ne pas pouvoir compter sur les ID D'emplacement pour définir les relations si vous voulez SaveChanges seulement plus tard.
Permute la ligne suivante...
LocationId = locations[i].Id
...pour cela...
Location = locations[i]
Les relations seront alors basées sur des références d'objets qui ne dépendent pas des LocationIDs.
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 base de données (et modèle généré à partir de DB).
J'avais des tables:
Parent (1-1) Child (1-many) Grandchild
Et la table petit-enfant avait reçu par inadvertance une clé étrangère jusqu'à son parent (enfant) et son grand-parent (Parent). Lors de l'enregistrement de plusieurs entités parentes à partir de new, j'ai reçu cette erreur. 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 le code EF d'abord, 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 sont 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 se plaindra sur Insert, plutôt que lorsque vous migrez-même si la vérité est une fois que la Migration s'exécute vous avez une table EF ne vous laissera jamais insérer dans.
La seule façon de rendre une référence récursive au même travail de 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 le int
.
Pour ceux qui recherchent cette exception:
Dans mon cas, il ne parvenait pas à définir une propriété de navigation requise.
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 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<LocationInRoute>();
for(....){
var lInRoute = new LocationInRoute(){
....
Route=insertedRoute;
}
insertedRoute.LocationInRoute.Add(lInRoute );
}