Mehrere hinzugefügte Entitäten können denselben Primärschlüssel haben

81

Hier ist mein Modell von 3 Entitäten: Route, Location und LocationInRoute.
Modell-

Die folgende Methode schlägt fehl und erhält beim Festschreiben eine Ausnahme:

 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;
        }

Dabei:

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

Ich habe:

Das Hauptende der Beziehung 'SimTaskModel.FK_T_STF_SUB_LOCATION_IN_ROUTE_T_STF_LOCATION_location_id' kann nicht ermittelt werden. Mehrere hinzugefügte Entitäten können denselben Primärschlüssel haben.

Beim Aufteilen des Commits und Einfügen in das Methos funktioniert es:

  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;
            }

Ich möchte Commit einmal und außerhalb der Methode aufrufen. Warum schlägt es im ersten Beispiel fehl und was bedeutet diese Ausnahme?

Naor
quelle
9
@ Ladislav Mrnka: Ich habe keinen Chef und das ist ein Projekt von mir. Ich weiß wirklich nicht, woher Sie den Eindruck haben, dass ich SO sofort frage. Sie sind nicht der einzige, der den ganzen Tag den Computer benutzt. Beratung kostenlos? Gibt jemand jemandem eine Garantie für seine Antworten? Ich glaube, dies ist ein Forum, in dem hier Fragen gestellt werden können, und das ist, was ich tue. Ich habe viele Fragen und ich glaube, dass ich dank dieses Forums und Menschen wie Ihnen viel lernen kann. Die Teilnahme ist eine Wahl.
Naor
1
@Ladislav: Ich sehe nur eine einigermaßen gut gestellte Frage, und das Profil des OP zeigt auch nichts übertriebenes an.
Henk Holterman
Verwenden Sie im gesamten Betriebsbereich denselben ObjectContext, oder verfügt jedes neue Repository über einen eigenen ObjectContext?
Akash Kava
@Akash Kava: Ich verwende den gleichen ObjectContext.
Naor

Antworten:

144

Der Fehler wird durch eine Fremdschlüssel-ID (im Gegensatz zu einer Referenz) verursacht, die nicht behoben werden kann. In Ihrem Fall haben Sie eine LocationInRole, die auf einen Standort mit einer ID von 0 verweist. Es gibt mehrere Standorte mit dieser ID.

Den Standorten wurde noch keine ID zugewiesen, da sie zum Zeitpunkt der Generierung der ID noch nicht in der Datenbank gespeichert wurden. In Ihrem zweiten Beispiel werden die Standorte gespeichert, bevor auf ihre IDs zugegriffen wird. Deshalb funktioniert dies.

Sie können sich beim Definieren der Beziehungen nicht auf die Standort-IDs verlassen, wenn Sie SaveChanges erst später speichern möchten.

Tauschen Sie die folgende Zeile aus ...

LocationId = locations[i].Id

...dafür...

Location = locations[i]

Die Beziehungen basieren dann auf Objektreferenzen, die nicht von den LocationIDs abhängig sind.

Scott Munro
quelle
Kann einer von euch einen Blick auf meinen Beitrag werfen und mir sagen, wie ich ihn beheben kann ? Ich bekomme das gleiche Problem: stackoverflow.com/questions/26783934/… Ich weiß das zu schätzen!
Duxfox
Ich erhalte diesen Fehler, wenn ich zum Testen von env bereitstelle ... nicht in dev environemnet irgendwelche Ideen?
Taran
@Taran Wenn der Code identisch ist und Sie in beiden Umgebungen denselben Prozess zum Testen verwenden (ich würde diese Punkte überprüfen), erscheint dies seltsam. Vielleicht fügen Sie in dev nur einen einzigen Speicherort hinzu (siehe Beispiel hier)? Versuchen Sie, mindestens zwei hinzuzufügen.
Scott Munro
Mein Problem könnte eine Variation davon sein. Ich habe die untergeordneten Objekte zur übergeordneten Sammlung hinzugefügt, ohne die übergeordnete Eigenschaft für die untergeordneten Objekte explizit festzulegen. Ich habe erwartet, dass EF dies behebt, aber den gleichen Fehler wie das OP erhalten, bis ich die übergeordnete Eigenschaft für das untergeordnete Element explizit festgelegt habe. Hoffe das hilft jemandem.
Eric H
4

Falls dies für zukünftige Leser von Nutzen ist, war dieser Fehler in meinem Fall auf einen falsch konfigurierten Fremdschlüssel in meiner Datenbank (und ein aus der Datenbank generiertes Modell) zurückzuführen.

Ich hatte Tische:

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

und der Enkelkind-Tisch hatte versehentlich einen Fremdschlüssel bis zu seinem Elternteil (Kind) und seinem Großelternteil (Elternteil) erhalten. Beim Speichern mehrerer übergeordneter Entitäten aus neuen hat ich diesen Fehler erhalten. Fix war, den Fremdschlüssel zu korrigieren.

Paddy
quelle
In meinem Fall hatte ich (dumm) meine Primärschlüssel-Basistabelle genauso eingestellt wie meine Fremdschlüssel- Basistabelle und meine Primärschlüssel-Spalte genauso wie meine Fremdschlüssel- Spalte. Ich hoffe, das hilft jemandem.
Dave
2

Nachdem ich auf denselben Fehler gestoßen bin, vermute ich sehr, dass das eigentliche Problem die Definition des Standorts war. Einfach gesagt, in EF Code First wette ich, dass es so aussah:

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

Mit anderen Worten, in der Frage sind ParentLocation / ParentLocationId eine rekursive Referenz zurück zu dieser Tabelle.

Die ParentLocationId ist nicht nullbar. Das bedeutet, dass es mit einer 0 eingefügt wird und EF sich beim Einfügen beschwert, anstatt beim Migrieren - obwohl die Wahrheit ist, dass Sie nach dem Ausführen der Migration eine Tabelle haben, in die EF Sie niemals einfügen lässt.

Die einzige Möglichkeit, eine rekursive Referenz auf dieselbe Tabelle zurückzusetzen, besteht darin, die rekursive Referenz auf Null zu setzen:

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

Beachten Sie die ?nach dem int.

Chris Moschini
quelle
Würde die alte (nicht nullfähige) Version nicht funktionieren, wenn Sie SaveChanges am übergeordneten Speicherort ausführen, bevor Sie den untergeordneten Speicherort erstellen?
André Kops
1
Ignoriere oben, ich bin ein Idiot. Sie könnten den ersten Speicherort nicht erstellen.
André Kops
Die Kardinalität war das Problem. Richtig.
Aclalex
0

Für diejenigen, die nach dieser Ausnahme suchen:
In meinem Fall konnte keine erforderliche Navigationseigenschaft festgelegt werden.

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
R. Salisbury
quelle
0

Ich hatte das gleiche Problem. mit unten Szenario für mich gelöst. Ich denke, Sie müssen Ihren Code wie folgt ändern:

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

insertedRoute.LocationInRoute.Add(lInRoute );
}
Ahmadreza Farrokhnejad
quelle