Wiele dodanych jednostek może mieć ten sam klucz podstawowy


81

Oto mój model 3 jednostek: Route, Location i LocationInRoute.
Model

poniższa metoda zawodzi i otrzyma wyjątek po jej zatwierdzeniu:

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

Robiąc:

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

Mam:

Nie można określić głównego końca relacji „SimTaskModel.FK_T_STF_SUB_LOCATION_IN_ROUTE_T_STF_LOCATION_location_id”. Wiele dodanych jednostek może mieć ten sam klucz podstawowy.

Podczas dzielenia zatwierdzenia i wstawiania do methos - działa:

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

Chciałbym wywołać commit raz i poza tą metodą. Dlaczego zawodzi w pierwszym przykładzie i co oznacza ten wyjątek?


9
@Ladislav Mrnka: Nie mam szefa i to jest mój projekt. Naprawdę nie wiem, skąd masz wrażenie, że od razu pytam na SO. Nie jesteś jedynym, który używa komputera przez cały dzień. Doradztwo za darmo? czy ktoś udziela komukolwiek gwarancji za swoje odpowiedzi? Myślę, że jest to forum, na którym można zadawać pytania i to właśnie robię. Mam wiele pytań i wierzę, że dzięki temu forum i ludziom takim jak Ty uczę się na odległość. Udział jest wyborem.
Naor

1
@Ladislav: Widzę tylko dość dobrze zadane pytanie, a profil OP również nie wskazuje niczego przesadnego.
Henk Holterman

Czy używasz tego samego ObjectContext w całym zakresie operacji, czy każde nowe repozytorium będzie miało własny ObjectContext?
Akash Kava

@Akash Kava: Używam tego samego ObjectContext.
Naor

Odpowiedzi:


144

Błąd jest spowodowany identyfikatorem klucza obcego (w przeciwieństwie do odwołania), którego nie można rozwiązać. W Twoim przypadku masz LocationInRole, która odwołuje się do lokalizacji o identyfikatorze 0. Istnieje wiele lokalizacji o tym identyfikatorze.

Lokacjom nie przypisano jeszcze identyfikatora, ponieważ nie zostały one jeszcze zapisane w bazie danych, w której jest generowany identyfikator. W drugim przykładzie lokalizacje są zapisywane przed uzyskaniem dostępu do ich identyfikatorów, dlatego to działa.

Nie będziesz mógł polegać na identyfikatorach lokalizacji w celu zdefiniowania relacji, jeśli chcesz zapisać zmiany dopiero później.

Zamień następującą linię ...

LocationId = locations[i].Id

...dla tego...

Location = locations[i]

Relacje będą wówczas oparte na odwołaniach do obiektów, które nie są zależne od identyfikatorów lokalizacji.


czy któryś z was może rzucić okiem na mój post i powiedzieć, jak mogę to naprawić, pojawia się ten sam problem: stackoverflow.com/questions/26783934/… Doceniam to!
duxfox

Otrzymuję ten błąd podczas wdrażania w celu przetestowania środowiska ... a nie w środowisku deweloperskim żadnych pomysłów?
Taran

@Taran Jeśli kod jest identyczny i używasz tego samego procesu do testowania w obu środowiskach (sprawdziłbym te punkty), wydaje się to dziwne. Może dodajesz tylko jedną lokalizację (zgodnie z przykładem tutaj) w programie dev? Spróbuj dodać co najmniej dwa.
Scott Munro

Mój problem może być odmianą tego. Dodawałem obiekty podrzędne do kolekcji rodzica bez jawnego ustawiania właściwości rodzica na dzieciach. Spodziewałem się, że EF rozwiąże ten problem, ale otrzymałem ten sam błąd co OP, dopóki wyraźnie nie ustawię właściwości nadrzędnej na dziecku. Mam nadzieję, że to komuś pomoże.
Eric H

4

W przypadku, gdy jest to przydatne dla przyszłych czytelników, w moim przypadku ten błąd był spowodowany nieprawidłowo skonfigurowanym kluczem obcym w mojej bazie danych (i modelu wygenerowanym z bazy danych).

Miałem tabele:

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

a tabela wnuków przypadkowo otrzymała klucz obcy do swojego rodzica (dziecka) i dziadka (rodzica). Podczas zapisywania wielu podmiotów nadrzędnych z nowego, otrzymałem ten błąd. Poprawka polegała na poprawieniu klucza obcego.


W moim przypadku (głupio) ustawiłem moją podstawową tabelę kluczy podstawowych tak samo, jak moją tabelę bazową kluczy obcych, a kolumnę kluczy podstawowych tak samo, jak moja kolumna klucza obcego pochyla głowę ze wstydem Mam nadzieję, że to komuś pomoże ...
Dave

3

Po napotkaniu tego samego błędu podejrzewam, że rzeczywistym problemem była definicja lokalizacji. Mówiąc prościej, w EF Code First założę się, że wyglądało to tak:

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

Innymi słowy, w pytaniu ParentLocation / ParentLocationId są rekursywnymi odwołaniami do tej tabeli.

ParentLocationId nie dopuszcza wartości Nullable. Oznacza to, że zostanie wstawiony z 0, a EF będzie narzekać na wstawianie, a nie podczas migracji - nawet jeśli prawda jest taka, że ​​po uruchomieniu migracji masz tabelę EF, która nigdy nie pozwoli ci wstawić.

Jedynym sposobem, aby odwołanie rekurencyjne z powrotem do tej samej tabeli działało, jest ustawienie wartości nullable referencji rekurencyjnej:

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

Zwróć uwagę na ?po int.


Czy stara (niezawierająca wartości null) wersja nie zadziała, jeśli wykonasz SaveChanges w lokalizacji nadrzędnej przed utworzeniem lokalizacji podrzędnej?
André Kops

1
Zignoruj ​​powyżej, jestem idiotą. Nie byłbyś w stanie stworzyć pierwszej lokalizacji.
André Kops

Problemem była liczność. Poprawny.
aclalex

0

Dla tych, którzy szukają tego wyjątku: w
moim przypadku nie udało się ustawić wymaganej właściwości nawigacji.

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

miałem ten sam problem. z poniższym scenariuszem rozwiązanym dla mnie. myślę, że musisz zmienić swój kod, taki jak poniżej:

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

insertedRoute.LocationInRoute.Add(lInRoute );
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.