EF 5, объект обновления выдает "Произошло нарушение ограничения ссылочной целостности"

В моей модели у меня есть куча доменных объектов. Теперь у меня проблема при попытке обновить пользовательский объект. Пользователь имеет отношение внешнего ключа к объекту Роль. Когда я обновляю объект User без изменения значения внешнего ключа (FkRoleId), все работает нормально. Но когда я изменяю роль для текущего пользователя, я хочу обновить, я получаю сообщение об ошибке:

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

Вот как я обновляю свой пользовательский объект:

public void Update(User user)
{
    using (var context = new DBEntities())
    { 
    context.Entry(user).State = System.Data.EntityState.Modified;
    context.SaveChanges();
    }
}

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

Вот мои классы домена в этом случае:

public partial class User
{
public User()
{
    this.Advertisers = new HashSet<Advertiser>();
    this.Cases = new HashSet<Case>();
    this.Materials = new HashSet<Material>();
}

public int PkId { get; set; }
public int FkRoleId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public System.DateTime Created { get; set; }
public bool Active { get; set; }

public virtual ICollection<Advertiser> Advertisers { get; set; }
public virtual ICollection<Case> Cases { get; set; }
public virtual ICollection<Material> Materials { get; set; }
public virtual Role Role { get; set; }
}


public partial class Role
{
public Role()
{
    this.Users = new HashSet<User>();
}

public int PkId { get; set; }
public string Name { get; set; }
public string Description { get; set; }

public virtual ICollection<User> Users { get; set; }
}

2 ответа

Решение

Чтобы процитировать ваш комментарий:

Тем не мение; если я установил свойство навигации user.Role в значение null, оно будет работать нормально. Но это рекомендуемый способ работы?

Да, в этом случае это так.

Вы должны иметь в виду, что вы вводите новый контекст с отдельным объектом user (включая ссылку на user.Role). Устанавливая состояние в Modified Вы прикрепляете объект user вместе с соответствующими user.Role в этом новом контексте.

Поскольку вы используете связь с внешним ключом - это означает, что внешний ключ представлен свойством FkRoleId в классе модели - связь описывается двумя способами: с помощью свойства навигации user.Role и скалярным свойством user.FkRoleId, Если они не соответствуют - то есть user.Role.PkId != user.FkRoleId - EF не знает, какая из них описывает правильные отношения, и выдает исключение, которое у вас есть.

Если вы установите user.Role в null EF рассмотрит user.FkRoleId отдельно, поскольку свойство, которое описывает отношения между пользователем и ролью, и неоднозначность, вызвавшую исключение, удаляется.

Для поисковиков я получил ту же ошибку, но нашел быстрое решение.

Я загружал класс с отношением FK в представление для редактирования. Даже без изменений FK удалялся, и эта ошибка произошла. Исправление заключалось в том, чтобы включить скрытое поле в представление Razor, содержащее FK. например

@Html.HiddenFor(model => model.ReleaseInfo.BookId)

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

Действия контроллера

public ActionResult Edit(int id = 0)
        {
            Book book = db.Books.Find(id);
            if (book == null)
            {
                return HttpNotFound();
            }
            ViewBag.Id = new SelectList(db.ReleaseInfo, "BookId", "BookId", book.Id);
            return View(book);
        }

        //
        // POST: /Book/Edit/5

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(Book book)
        {
            if (ModelState.IsValid)
            {
                db.Entry(book).State = EntityState.Modified;

                db.SaveChanges();
                return RedirectToAction("Index");
            }
            ViewBag.Id = new SelectList(db.ReleaseInfo, "BookId", "BookId", book.Id);
            return View(book);
        }

Отношения

Book.cs

  public class Book
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }

        [Required]
        [MaxLength(100)]
        public string Title { get; set; }


        public virtual ICollection<Author> Authors { get; set; }


        public virtual ReleaseInfo ReleaseInfo { get; set; }


        public virtual ICollection<ReRelease> ReReleases { get; set; }

    }

ReleaseInfo.cs

public class ReleaseInfo
    {
        // One to one relationship uses Books Key as Key.
        [Key, ForeignKey("Book")]
        public int BookId { get; set; }

        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        public DateTime ReleaseDate { get; set; }


        public virtual Book Book { get; set; }
    }
Другие вопросы по тегам