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