33

Вопрос по entity-framework, c# – Entity Framework: Нарушение ограничения ссылочной целостности в отношениях «многие ко многим»

Эй, у меня есть приложение с кучей кэширования inproc и структурой сущностей. Когда я хочу записать обновление для объекта, я снова присоединяю кешированную копию. Я отслеживаю все вещи, которые я прикрепил в жизненном цикле контекста, поэтому я не пытаюсь прикрепить их дважды.

У меня ошибка при присоединении (очень редко в большинстве случаев это работает нормально и очень быстро), которая говорит следующее:

A referential integrity constraint violation occurred: The property values that define the referential constraints are not consistent between principal and dependent objects in the relationship.

Я действительно внимательно посмотрел на объект, который выглядит нормально. Я думаю, что эта проблема связана с прикреплением / отсоединением внешнего ключа во время выполнения исправлений.

Есть ли хороший способ получить дополнительную информацию об этой ошибке или она может возникнуть по причинам, отличным от того, что объект находился в состоянии, которого EF не ожидал?

РЕДАКТИРОВАТЬ: Диаграмма БД (обратите внимание, что я использую codefirst, я просто использовал инструмент EDMX, чтобы сделать диаграмму, я также отобрал несколько регулярных свойств из модели для простоты)

enter image description here

  • По моему сценариюCategoryс иBusiness, Каждый бизнес может иметь несколькоCategorys. У меня есть список идентификаторов категорий, которые я хочу прикрепить, как мне это сделать?

    от
  • Так как мне установитьLocationсPersonс (учитываяLocations идентификаторы)? В моем случае это проблема многих из многих. Каково общее решение этого исключения, как мне его обойти?

    от
  • @Shimmy: создание категорий заглушки (new Category { Id = id }), присоедините их к контексту, добавьте их вBusiness.Categories сбор и сохранение изменений. Но это кажется немного от этого вопроса и ответа. Возможно, создайте новый вопрос, чтобы получить более сфокусированные ответы.

    от
  • Вы помните, что все категории уже существуют в БД, прежде чем присоединять их PK к каждому бизнесу. Это правильно?

    от
  • @Shimmy: либо установите свойство FK, оставляя свойство навигации какnull (что я бы сделал в этом случае) или убедитесь, что значение свойства FK и значение PK объекта, установленного для свойства навигации, совпадают. Но в моем понимании это исключение не может происходить для отношений «многие ко многим». Это исключение, относящееся только к ассоциациям FK, и отношения "многие ко многим" являются независимыми ассоциациями, а не ассоциациями FK.

    от
  • Используете ли вы сначала код или модель в первую очередь - и любую дополнительную информацию о вашей модели, таблицах / классах, которые относятся к ошибке, и как отображается соотношение «многие ко многим». В случае, если вы сначала используете код, я предпочитаю установить отношение «вручную»; так что я могу контролировать все аспекты и избегать подобных вещей. С другой стороны, ошибка ссылочной целостности, вероятно, будет означать именно это - я не думаю, что это состояние объекта, хотя она может проявляться аналогичным образом, как я полагаю.

    от NSGaga
  • Я использую CodeFirst, моя модель очень проста, плохо выложить диаграмму в секунду

    от Luke McGregor
  • Люк, можешь дать часть CF, как ты сопоставляешь вещи - как выглядят твои классовые модели, твой код миграции? Чтобы быть в состоянии помочь любому с этим.

    от NSGaga
6 ответов
  • 0

    У меня была эта проблема

    и я нашел довольно быстрое решение. Моя проблема была со многими-многими таблицами.

    Public class Pictures_Tag
    {
        [Key]
        [Column(Order = 0)]
        [ForeignKey("Picture")]
        public Int16 Picture_ID { get; set; }
        [Key]
        [Column(Order = 1)]
        [ForeignKey("ImageTag")]
        public Int16 ImageTag_ID { get; set; }
        public virtual Picture Picture { get; set; }
        public virtual ImageTag ImageTag { get; set; }
    }
    

    Я добавил строку, где я назначилPicture = db.Pictures... и тогда он работал нормально (не совсем уверен, почему)

    [HttpPost]
    public ActionResult Edit2(WebSiteEF2017C.Models.Pictures_Tag p)
    {     
        using (var db = new thisModel(Session["org"].ToString())
        {
             p.Picture = db.Pictures.Where(z => z.ID == p.Picture_ID).FirstOrDefault();
             db.Pictures_Tags.Attach(p);
             db.Entry(p).State = EntityState.Modified;
             db.SaveChanges();
             return View(db.Pictures_Tags.Include(x => x.Picture)
                        .Where(n => n.Picture_ID == p.Picture_ID & n.ImageTag_ID == p.ImageTag_ID).FirstOrDefault());
        }
    }
    

  • 1

    Чтобы добавить ответ @ Slauma

    это не просто при добавлении объектов в ваш контекст. Например, если вы редактируете CurrentLocationId в Person, вам также необходимо отредактировать объект CurrentLocation, встроенный в объект Person. EF автоматически заполнит объект CurrentLocation, поскольку у CurrentLocationId есть внешний ключ в таблице CurrentLocation. Когда вы редактируете CurrentLocationId без обновления также объекта CurrentLocation, они становятся не синхронизированными. Это то, что вызывает исключение в этом случае.

    Итак, допустим, вам нужно обновить CurrentLocationId объекта Person. Мы предполагаем, что вы предварительно загрузили данные о персоне и данные о местоположении.

    public class DbData 
    {
        List<Person> PersonList;
        List<Location> LocationList;
        public Db,Data()
        {
            using (var context = new MyContext())
            {
                 PersonList = context.Persons.ToList();
                 LocationList = context.Locations.ToList();
            }
        }
    
        public void UpdatePersonLocation(Person person, int newLocationId)
        {
            using (var context = new MyContext())
            {
                var location = LocationList.Where(l=>l.id==newLocationId).Single();
                //you need to update both the id and the location for this to not throw the exception
                person.CurrentLocationId == newLocationId;
                person.CurrentLocation == location;  
                context.Entry(person).State = System.Data.Entity.EntityState.Modified;
                context.SaveChanges();
            }
        }
        //or if you're giving it the location object...
        public void UpdatePersonLocation(Person person, Location location)
        {
            using (var context = new MyContext())
            {
                //you need to update both the id and the location for this to not throw the exception
                person.CurrentLocationId == location.id;
                person.CurrentLocation == location;  
                context.Entry(person).State = System.Data.Entity.EntityState.Modified;
                context.SaveChanges();
            }
        }
    }
    

  • 45

    Ошибка может возникнуть для отношения один ко многим между

    Person а такжеLocation вы, очевидно, имеете в своей модели в дополнение к отношениям многих ко многим. Например, следующий код выдает исключение:

    using (var context = new MyContext())
    {
        var person = new Person
        {
            CurrentLocationId = 1,
            CurrentLocation = new Location { Id = 2 }
        };
        context.People.Attach(person); // Exception
    }
    

    & quot; Значения свойств, которые определяют ссылочные ограничения & quot; являются значением свойства внешнего ключаCurrentLocationId и значение первичного ключаCurrentLocation.Id, Если эти значения отличаются, генерируется исключение. (НаличиеCurrentLocation какnull хотя разрешено.)

    По моему мнению, это исключение может быть выдано только для ассоциаций внешних ключей, потому что только для ассоциации такого типа у вас есть свойства, которые вообще определяют ссылочные ограничения в вашей модели. Это не может быть брошено для независимых ассоциаций. Поскольку каждое отношение «многие ко многим» является независимой ассоциацией (в модели отсутствует свойство внешнего ключа), я предполагаю, что ошибка связана не с вашим отношением «многие ко многим», а с отношением «один ко многим».

  • 2

    Я только что столкнулся с той же проблемой

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

    Чтобы решить проблему, мне пришлось открыть окно сопоставлений для ассоциации, и была ссылка для удаления сопоставлений. После того, как окно «Сведения о сопоставлении» выполнено, сказанное «Сопоставления не разрешены». Похоже, что добавление ссылочного ограничения оставляет все сопоставления на месте.

    Мысль может стоить опубликовать в случае, если кто-то еще ищет решения для этого сообщения об ошибке в будущем.

  • 1

    @ LukeMcGregor привет,

    Я думаю, что могу предложить другую точку зрения, как тот, у кого такая же проблема.

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

    Потому что в моем сценарии: я хотел включить объект, который вызвал ошибку несоответствия. Это объект местоположения в вашем сценарии. Если я добавляю объект с идентификатором, я получаю эту ошибку, потому что идентификатор в предыдущем объекте (тот, который не обновлен) не совпадает с обновленным идентификатором.

    Но это не большая проблема. Как решение; Если он все еще на стороне пользовательского интерфейса, объект все еще может быть включен, если он все еще существует.

    Вы либо очистите объект, когда получите запрос на обновление от пользователя. (= Null) Или вы обновите объект с идентификатором, обновленным пользователем перед обновлением на стороне службы (присоедините, изменили ... что угодно) и обновите его таким образом.

    Вот и все. Он может оставаться как есть в базе данных и на диаграммах.

  • 6

    Я столкнулся с очень похожим исключением:

    "A referential integrity constraint violation occurred: 
    The property value(s) of 'ObjectA.PropertyX' on one end of a relationship 
    do not match the property value(s) of 'ObjectB.PropertyY' on the other end."
    

    Причина была в следующем: Клиентская сторона веб-API отправила запрос PUT со всем объектом, включая свойство навигации (в этом примере ObjectA (точнее, ObjectB.ObjectA) было свойством навигации и было полностью предоставлено клиентом). Это происходит потому, что клиент получает весь объект с сервера и возвращает его как есть обратно на сервер с небольшими изменениями.

    С другой стороны, ObjectB.PropertyY был только что изменен (это было причиной запроса PUT в первую очередь).

    Поскольку ObjectB.PropertyY был ссылкой на тот же объект ObjectA (внешний ключ), EF попытался согласовать это и потерпел неудачу с вышеуказанным исключением.

    Решение было простым:

    ObjectB.ObjectA = null;
    

    до того, как SaveChanges () решил это полностью.

    Я надеюсь, что это помогает кому-то.