Пытаюсь удалить элемент из коллекции UsersVaults объекта типа User, но получаю Exception (текст ошибки и код ниже). Подскажите, где я повернул не туда?
Метод изменения объекта:
[HttpPost]
public ActionResult Edit(int id, FormCollection form)
{
try
{
using (var db = new AccessControlSystemDatabaseModel())
{
var user = db.Users.Find(id);
var tempData = form.AllKeys.ToDictionary
user.RoleID = Convert.ToInt32(tempData["RoleID"]);
user.Username = tempData["Username"].ToString();
user.Password = tempData["Password"].ToString();
user.Email = tempData["Email"].ToString();
if (!tempData["GrantAccess"].ToString().Equals("false") && user.UsersVaults.Where(
d => d.VaultID == AuthenticationController.CurrentUser.UsersVaults.ToList()[0].VaultID)
.ToList()
.Count == 0)
{
user.UsersVaults.Add(new UsersVault
{
UserID = id,
VaultID = AuthenticationController.CurrentUser.UsersVaults.ToList()[0].VaultID,
});
}
else
{
var tt =
user.UsersVaults.Where(
d => d.VaultID == AuthenticationController.CurrentUser.UsersVaults.ToList()[0].VaultID).ToList()[0];
user.UsersVaults.Remove(tt);
}
db.Entry(user).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch(Exception e)
{
return RedirectToAction("Index");
}
}
Модель:
public partial class AccessControlSystemDatabaseModel : DbContext
{
public AccessControlSystemDatabaseModel()
: base("name=AccessControlSystemDatabaseModel")
{
}
public virtual DbSet
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity
modelBuilder.Entity
public partial class Role
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Role()
{
Users = new HashSet
public int ID { get; set; }
[Required]
[StringLength(255)]
public string RoleName { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection
public partial class User
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public User()
{
UsersVaults = new HashSet
public int ID { get; set; }
[Required]
[StringLength(255)]
public string Username { get; set; }
[Required]
[StringLength(255)]
public string Password { get; set; }
public int? RoleID { get; set; }
[StringLength(255)]
public string Email { get; set; }
public virtual Role Role { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection
public partial class UsersVault
{
public int ID { get; set; }
public int UserID { get; set; }
public int VaultID { get; set; }
public virtual User User { get; set; }
public virtual Vault Vault { get; set; }
}
public partial class Vault
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Vault()
{
UsersVaults = new HashSet
public int ID { get; set; }
[Required]
[StringLength(255)]
public string VaultName { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection
Текст исключения:
"Операция завершилась с ошибкой. Не удалось изменить связь, поскольку один или несколько свойств внешнего ключа не допускают значения NULL. При изменении связи соответствующему свойству внешнего ключа присваивается значение NULL. Если внешний ключ не поддерживает значений NULL, должна быть определена новая связь, свойству внешнего ключа должно быть присвоено другое значение, отличное от NULL, либо необходимо удалить несвязанный объект."
Ответ
В EF, к сожалению, операции Add и Remove для навигационных коллекций не всегда симметричны - первая операция устанавливает связь между сущностями и при необходимости добавляет их в базу, вторая же только разрывает связь. Но разорвать связь между UsersVault и User невозможно, отсюда и ошибка.
Поэтому надо вместо удаления объекта из коллекции явно удалить его из базы:
var tt = user.UsersVaults.Single(...);
db.Entry(tt).State = EntityState.Deleted;
или
db.UsersVaults.Remove(tt);
Для сохранения симметричности операций, можно при добавлении UsersVault точно так же сразу добавлять его в базу:
db.UsersVaults.Add(new UsersVault
{
UserID = id,
VaultID = ...,
})
Кстати, в вашем текущем коде есть дублирование - UserID присваивать не обязательно если вы добавляете объект через навигационную коллекцию - EF проставит его сама.
В качестве альтернативного решения могу предложить вообще удалить сущность UsersVault - она не нужна! EF умеет самостоятельно отображать связи "многие-ко-многим" на промежуточные таблицы, просто создайте mtm-связь между Users и Vaults
Комментариев нет:
Отправить комментарий