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 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?

63
demandé sur Sefe 2011-05-18 11:06:28

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.

127
répondu Scott Munro 2011-08-07 02:39:10

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.

4
répondu Paddy 2016-01-21 14:55:52

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.

0
répondu Chris Moschini 2016-10-14 21:04:16

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
0
répondu R. Salisbury 2017-05-23 13:44:53

, 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 );
}
0
répondu Ahmadreza Farrokhnejad 2017-12-16 06:58:12