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