Несколько добавленных объектов могут иметь один и тот же первичный ключ - PullRequest
70 голосов
/ 18 мая 2011

Вот моя модель из 3 объектов: Маршрут, Местоположение и Местоположение в пути.
model

следующий метод завершается ошибкой и получает исключение при его фиксации:

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

При выполнении:

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

Я получил:

Невозможно определить основной конец отношения SimTaskModel.FK_T_STF_SUB_LOCATION_IN_ROUTE_T_STF_LOCATION_location_id. Несколько добавленных объектов могут иметь один и тот же первичный ключ.

При разбиении коммита и вставке в метод - это работает:

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

Я хотел бы вызвать commit один раз и за пределами метода. Почему это не удается в первом примере и что означает это исключение?

Ответы [ 5 ]

132 голосов
/ 07 августа 2011

Ошибка вызвана идентификатором внешнего ключа (в отличие от ссылки), который невозможно устранить.В вашем случае у вас есть LocationInRole, который ссылается на местоположение с идентификатором 0. Существует несколько местоположений с этим идентификатором.

Местоположениям еще не был присвоен идентификатор, поскольку они еще не были сохранены вбаза данных, когда идентификатор генерируется.Во втором примере местоположения сохраняются до доступа к их идентификаторам, поэтому это работает.

Вы не сможете полагаться на идентификаторы местоположения для определения отношений, если хотите сохранить изменения только позже.

Поменяйте местами следующую строку ...

LocationId = locations[i].Id

... для этого ...

Location = locations[i]

Тогда отношения будут основываться на ссылках на объекты, которые не являютсязависит от идентификатора местоположения.

4 голосов
/ 21 января 2016

В случае, если это пригодится будущим читателям, в моем случае эта ошибка произошла из-за неправильно настроенного внешнего ключа в моей базе данных (и модели, сгенерированной из БД).

У меня были таблицы:

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

и таблица Grandchild непреднамеренно получила внешний ключ вплоть до своего родителя (Child) и своего деда (Parent).При сохранении нескольких родительских объектов из новой я получил эту ошибку.Исправлено исправление внешнего ключа.

1 голос
/ 20 сентября 2016

Я столкнулся с той же ошибкой, и я подозреваю, что проблема заключалась в определении местоположения.Проще говоря, в EF Code First я уверен, что это выглядело так:

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

Другими словами, в Вопросе ParentLocation / ParentLocationId - это рекурсивная ссылка на эту таблицу.

ParentLocationId не имеет значения Nullable.Это означает, что он будет вставлен с 0, и EF будет жаловаться на вставку, а не когда вы выполняете миграцию - даже если правда, что после запуска миграции у вас есть таблица, в которую EF никогда не разрешит вставлять.

Единственный способ сделать рекурсивную ссылку обратно на ту же работу таблицы - сделать рекурсивную ссылку обнуляемой:

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

Обратите внимание на ? после int.

0 голосов
/ 16 декабря 2017

У меня была такая же проблема.с сценарием ниже, решенным для меня.я думаю, что вы должны изменить свой код, например ниже:

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

insertedRoute.LocationInRoute.Add(lInRoute );
}
0 голосов
/ 23 мая 2017

Для тех, кто ищет это исключение:
В моем случае не удалось установить обязательное свойство навигации.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...