81 votes

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

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

la méthode suivante échoue et obtient une exception lors de sa 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;
        }

Quand on le fait :

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

J'ai eu :

Impossible de déterminer l'extrémité 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.

En divisant le commit et en l'insérant 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-t-il dans le premier exemple et que signifie cette exception ?

9 votes

@Ladislav Mrnka : Je n'ai pas de patron et c'est mon projet. Je ne sais vraiment pas d'où vous vient l'impression que je demande immédiatement sur SO. Vous n'êtes pas le seul à utiliser l'ordinateur toute la journée. Une consultation gratuite ? Quelqu'un donne-t-il une garantie pour ses réponses ? Je crois que c'est un forum où l'on peut poser des questions et c'est ce que je fais. J'ai beaucoup de questions et je crois que je fais un long chemin d'apprentissage grâce à ce forum et à des gens comme vous. La participation est un choix.

1 votes

@Ladislav : Je ne vois qu'une question raisonnablement bien posée, et le profil de l'OP n'indique rien d'excessif non plus.

0 votes

Utilisez-vous le même ObjectContext dans tout le périmètre d'opération ou chaque nouveau dépôt aura son propre ObjectContext ?

148voto

Scott Munro Points 4008

L'erreur est causée par un ID de clé étrangère (par opposition à une référence) qui ne peut ê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 lieux n'ont pas encore reçu d'identifiant car ils n'ont pas encore été enregistrés dans la base de données, ce qui permet de générer l'identifiant. Dans votre deuxième exemple, les lieux sont sauvegardés avant que l'on accède à leurs identifiants, c'est pourquoi cela fonctionne.

Vous ne pourrez pas vous appuyer sur les ID d'emplacement pour définir les relations si vous ne voulez enregistrer les modifications que plus tard.

Remplacez la ligne suivante...

LocationId = locations[i].Id

...pour ce...

Location = locations[i]

Les relations seront alors basées sur des références d'objets qui ne dépendent pas des LocationIDs.

0 votes

Est-ce que l'un d'entre vous peut jeter un coup d'œil à mon post et me dire comment le réparer, j'ai le même problème : stackoverflow.com/questions/26783934/ Je l'apprécie !

0 votes

J'obtiens cette erreur lorsque je déploie dans l'environnement de test... mais pas dans l'environnement de développement... Des idées ?

0 votes

@Taran Si le code est identique et que vous utilisez le même processus pour tester dans les deux environnements (je vérifierais ces points) alors cela semble étrange. Peut-être n'ajoutez-vous qu'un seul emplacement (en suivant l'exemple ici) dans dev ? Essayez d'en ajouter au moins deux.

4voto

Paddy Points 16834

Au cas où cela serait utile aux futurs lecteurs, dans mon cas, cette erreur était due à une clé étrangère incorrectement configurée dans ma base de données (et le modèle généré à partir de la BD).

J'avais des tables :

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

et la table Grandchild avait reçu par inadvertance une clé étrangère jusqu'à son parent (Child) et son grand-parent (Parent). Lors de la sauvegarde de plusieurs entités Parent à partir d'un nouveau fichier, j'ai reçu cette erreur. La solution a été de corriger la clé étrangère.

3voto

Chris Moschini Points 7278

Ayant rencontré la même erreur, je soupçonne fortement que le problème réel était la définition de Location. Pour faire simple, dans le code EF First, je parie que ça ressemblait à ça :

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 lors de l'insertion, plutôt que lors de la migration - même si la vérité est qu'une fois la migration lancée, vous avez une table dans laquelle EF ne vous laissera jamais insérer.

La seule façon de faire fonctionner 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 le int .

0voto

R. Salisbury Points 1282

Pour ceux qui recherchent cette exception :
Dans mon cas, il n'a pas réussi à 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

0voto

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<LocationInRoute>();
for(....){
    var lInRoute = new LocationInRoute(){
    ....
    Route=insertedRoute;
}

insertedRoute.LocationInRoute.Add(lInRoute );
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X