操作失败:无法更改关系,因为一个或多个外键属性不可为空.当对关系进行更改时,将相关的外键属性设置为空值.如果外键不支持空值,则必须定义新关系,必须为外键属性分配另一个非空值,否则必须删除不相关的对象.
从其他帖子,我明白使用Remove(entity)标记该实体进行删除.在SaveChanges中,EF将外键设置为Null,并发生上述错误.
我发现在子实体上使用DeleteObject而不是Remove的一些帖子;但是,由于添加了dbContext和DbSet,因此DeleteObject方法似乎已被删除.
我发现建议修改EDMX外键关系为Nullable的帖子.修改EDMX是很好的,但是当数据库的更新模型完成时,这些更改将被禁用,并且必须重新应用.不是最佳的.
另一个帖子建议创建一个外键关系设置为Nullable的代理实体,但我不明白这种方法.它似乎与修改EDMX相同的问题,因为当保存对EDMX的更改时,上下文会自动更新.
我的简化模型是:
public partial class User { public User() { this.UserContacts = new HashSet<UserContact>(); } public long userId { get; set; } public string userEmail { get; set; } public string userPassword { get; set; } public string userFirstName { get; set; } public string userLastName { get; set; } . . . public virtual Country Country { get; set; } public virtual State State { get; set; } public virtual ICollection<UserContact> UserContacts { get; set; } }
}
public partial class UserContact { public long userContactId { get; set; } public long userContactUserId { get; set; } public long userContactTypeId { get; set; } public string userContactData { get; set; } public virtual ContactType ContactType { get; set; } public virtual User User { get; set; } }
userContactUserId和userContactTypeId是必需的外键.
在dbContext容器中,Users和UserContact都是DbSet.
我有一个viewmodel的用户和一个viewmodel的UserContact如下
public class UserContactviewmodel { [HiddenInput] public long UserContactId { get; set; } [HiddenInput] public long UserContactUserId { get; set; } [Display(Name = "Contact")] [required] public string ContactData { get; set; } [required] public long ContactType { get; set; } [HiddenInput] public bool isDeleted { get; set; } } public class MyProfileviewmodel { [HiddenInput] public long UserId { get; set; } [required] [Display(Name = "First Name")] [StringLength(100)] public string FirstName { get; set; } [required] [StringLength(100)] [Display(Name = "Last Name")] public string LastName { get; set; } .... public IEnumerable<UserContactviewmodel> Contacts { get; set; } }
将更改保存到用户配置文件时,我会循环使用UserContactviewmodel实体列表,以确定哪些已添加,修改或删除.
foreach (var c in model.Contacts) { UserContact uc = usr.UserContacts.Single(con => con.userContactId == c.UserContactId); if (uc != null) { if (c.isDeleted == true) // Deleted UserContact { ctx.UserContacts.Remove(uc); // Remove doesn't work } else // Modified UserContact { uc.userContactData = c.ContactData; uc.userContactTypeId = c.ContactType; ctx.Entry(uc).State = EntityState.Modified; } } else // New UserContact { usr.UserContacts.Add(new UserContact { userContactUserId = model.UserId,userContactData = c.ContactData,userContactTypeId = c.ContactType }); } }
我会感谢任何帮助.
解决方法
首先,我可以通过将DbContext(例如“ctx”)转换为IObjectContextAdapter并获取对ObjectContext的引用来获取ObjectContext.
接下来,我简单地称之为DeleteObject方法传递要删除的UserContact记录.
if (c.isDeleted == true) // Deleted UserContact { ObjectContext oc = ((IObjectContextAdapter)ctx).ObjectContext; oc.DeleteObject(uc) }
以下是相关代码片段:
foreach (var c in model.Contacts) { UserContact uc = null; if (c.UserContactId != 0) { uc = ctx.UserContacts.Find(c.UserContactId); } if (uc != null) { if (c.isDeleted == true) // Deleted UserContact { ObjectContext oc = ((IObjectContextAdapter)ctx).ObjectContext; oc.DeleteObject(uc); } else // Modified UserContact { uc.userContactData = c.ContactData; uc.userContactTypeId = c.ContactType; ctx.Entry(uc).State = EntityState.Modified; } } else // New UserContact { usr.UserContacts.Add(new UserContact { userContactData = c.ContactData,userContactTypeId = c.ContactType }); } } ctx.Entry(usr).State = EntityState.Modified; ctx.SaveChanges();
希望这能帮助未来的人.