webentwicklung-frage-antwort-db.com.de

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

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

die folgende Methode schlägt fehl und erhält eine Ausnahme, wenn Sie sie festschreiben:

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

Wenn Sie:

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

Ich habe:

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

Beim Aufteilen von Commit und Insert in die Methode - es funktioniert:

  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 scheitert es im ersten Beispiel und was bedeutet diese Ausnahme?

69
Naor

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

Den Standorten wurde noch keine ID zugewiesen, da sie noch nicht in der Datenbank gespeichert wurden. Dies ist der Zeitpunkt, zu dem die ID generiert wird. In Ihrem zweiten Beispiel werden die Standorte gespeichert, bevor auf ihre IDs zugegriffen wird, weshalb dies funktioniert.

Sie können sich nicht auf die Standort-IDs verlassen, um die Beziehungen zu definieren, wenn Sie die Änderungen 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.

132
Scott Munro

Falls dies für zukünftige Leser von Nutzen ist, lag dieser Fehler in meinem Fall an einem falsch konfigurierten Fremdschlüssel in meiner Datenbank (und das aus der Datenbank generierte Modell).

Ich hatte Tische:

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

und der Enkelkindentisch hatte versehentlich einen Fremdschlüssel bis zu seinem Elternteil (Child) und seinem Großelternteil (Parent) erhalten. Beim Speichern mehrerer übergeordneter Entitäten aus neuen habe ich diesen Fehler erhalten. Problem wurde behoben, um den Fremdschlüssel zu korrigieren.

4
Paddy

Nach dem gleichen Fehler habe ich den Verdacht, dass das eigentliche Problem die Definition von Location 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 auf diese Tabelle.

Die ParentLocationId ist nicht nullfähig. Das bedeutet, es wird eine 0 eingefügt, und EF beschwert sich beim Einfügen und nicht beim Migrieren. Selbst wenn die Migration erst einmal ausgeführt wird, haben Sie eine Tabelle, in die EF Sie niemals einfügen können.

Die einzige Möglichkeit, einen rekursiven Verweis auf dieselbe Tabellenarbeit zurückzusetzen, besteht darin, den rekursiven Verweis 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 den ? hinter der int.

1
Chris Moschini

ich hatte das gleiche Problem. mit untenstehendem 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 );
}

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