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

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

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

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

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

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

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

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

Ответ 1

Процитировать ваш комментарий:

Тем не менее; если я установил свойство навигации 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, поскольку свойство, которое описывает взаимосвязь между пользователем и ролью, и неоднозначность, вызывающая исключение, удаляется.

Ответ 2

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

Я загружал класс с отношениями 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; }
    }