EntityFramework的文档声明可能存在以下行为:
如果依赖实体上的外键可以为空,则Code First会这样做 没有在关系上设置级联删除,当主体是 删除外键将被设置为null。
(来自http://msdn.microsoft.com/en-us/jj591620)
然而,我无法实现这样的行为。
我使用代码优先定义了以下实体:
public class TestMaster
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<TestChild> Children { get; set; }
}
public class TestChild
{
public int Id { get; set; }
public string Name { get; set; }
public virtual TestMaster Master { get; set; }
public int? MasterId { get; set; }
}
以下是Fluent API映射配置:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<TestMaster>()
.HasMany(e => e.Children)
.WithOptional(p => p.Master).WillCascadeOnDelete(false);
modelBuilder.Entity<TestChild>()
.HasOptional(e => e.Master)
.WithMany(e => e.Children)
.HasForeignKey(e => e.MasterId).WillCascadeOnDelete(false);
}
外键可以为空,导航属性被映射为可选,所以我希望级联删除工作如MSDN所述 - 即使所有子节点的MasterID无效,然后删除主对象。
但是当我实际尝试删除时,我收到了FK违规错误:
using (var dbContext = new TestContext())
{
var master = dbContext.Set<TestMaster>().Find(1);
dbContext.Set<TestMaster>().Remove(master);
dbContext.SaveChanges();
}
在SaveChanges()上,它会抛出以下内容:
System.Data.Entity.Infrastructure.DbUpdateException : An error occurred while updating the entries. See the inner exception for details.
----> System.Data.UpdateException : An error occurred while updating the entries. See the inner exception for details.
----> System.Data.SqlClient.SqlException : The DELETE statement conflicted with the REFERENCE constraint "FK_dbo.TestChilds_dbo.TestMasters_MasterId". The conflict occurred in database "SCM_Test", table "dbo.TestChilds", column 'MasterId'.
The statement has been terminated.
我做错了什么或者我误解了MSDN说的是什么?
答案 0 :(得分:44)
它确实如所描述的那样,但MSDN上的文章没有强调只有当孩子被加载到上下文时才有效,而不仅仅是父实体。因此,您必须使用Find
(或以任何其他方式将子项加载到上下文中)来使用Include
(仅加载父项),而不是使用using (var dbContext = new TestContext())
{
var master = dbContext.Set<TestMaster>().Include(m => m.Children)
.SingleOrDefault(m => m.Id == 1);
dbContext.Set<TestMaster>().Remove(master);
dbContext.SaveChanges();
}
:
Child
这将从数据库中删除master,将null
实体中的所有外键设置为{{1}},并将子项的UPDATE语句写入数据库。
答案 1 :(得分:0)
在关注@ Slauma的好答案后,我仍然得到与OP相同的错误。
所以不要像我一样天真,并认为下面的例子最终会得到相同的结果。
dbCtx.Entry(principal).State = EntityState.Deleted;
dbCtx.Dependant.Where(d => d.PrincipalId == principalId).Load();
// code above will give error and code below will work on dbCtx.SaveChanges()
dbCtx.Dependant.Where(d => d.PrincipalId == principalId).Load();
dbCtx.Entry(principal).State = EntityState.Deleted;
首先将子项加载到上下文 之前将实体状态设置为已删除(如果您这样做的话)。