And*_*lov 3 c# entity-framework entity-framework-6
我有以下型号的问题:
public class ProjectPage
{
[Key]
public Guid Id { get; set; }
public Guid? HeaderId { get; set; }
public ProjectPage Header { get; set; }
public Guid? FooterId { get; set; }
public ProjectPage Footer { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
在模型创建我有这个:
modelBuilder.Entity<ProjectPage>().HasOptional(p => p.Header).WithMany().HasForeignKey(p => p.HeaderId).WillCascadeOnDelete(true);
modelBuilder.Entity<ProjectPage>().HasOptional(p => p.Footer).WithMany().HasForeignKey(p => p.FooterId).WillCascadeOnDelete(true);
Run Code Online (Sandbox Code Playgroud)
但我无法更新数据库.我在Package Manager控制台中遇到以下错误:
在表'ProjectPages'上引入FOREIGN KEY约束'FK_dbo.ProjectPages_dbo.ProjectPages_FooterId'可能会导致循环或多个级联路径.指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束.
有人可以解释如何删除项目页面(可以是另一个项目页面中的页脚或页眉)?
如果有多个级联删除路径可能会导致尝试删除DB中的同一行,则会导致该异常.想象一下,如果你有ProjectPage同样的Header和Footer.当您尝试删除它时ProjectPage,由于您的关系配置,将有两条路径尝试删除DB中的同一行(一个用于Header另一个用于另一个用于Footer).
您可以通过使用Fluent API禁用两个关系之一中的级联删除,或者将某些关系定义为可选(使用可为空的外键,但无法使用级联删除配置关系)来避免此类不明确的删除路径.
是的,你有两个FK作为选项,但两个关系都配置了级联删除,这就是EF抛出异常的原因.我的建议只与级联删除设置了一个关系.关于其他关系,我担心你必须手动完成.例如,如果您选择Footer手动删除,那么当您要删除a时ProjectPage,您必须将该Footer属性设置为null.这里的问题是你的DB中可能有孤儿.为避免这种情况,您可以覆盖SaveChanges上下文以查找和删除孤儿:
public override int SaveChanges()
{
ProjectPages
.Local
.Where(r => r.Footer== null && r.FooterId!=default(Guid)).Select(r=>r.FooterId)
.ToList()
.ForEach(id => ProjectPages.Remove(ProjectPages.Find(id)));
return base.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)
另一种方法是FooterId使用default(Guid)值设置.由于PK属性(Id)的类型是Guid并且它不是Identity,因此必须在将ProjectPage数据添加到数据库之前设置该属性.因此,设置FooterIdwith default(Guid)是另一种标记要删除的实体的方法.如果您选择此变体,您的SaveChanges方法可能如下所示:
public override int SaveChanges()
{
ProjectPages
.Local
.Where(r => r.Footer!= null && r.FooterId!=default(Guid)).Select(r=>r.Footer)
.ToList()
.ForEach(pp=> ProjectPages.Remove(pp));
return base.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)
要么:
public override int SaveChanges()
{
ProjectPages
.Local
.Where(r => r.Footer!= null && r.FooterId!=default(Guid)).Select(r=>r.Footer)
.ToList()
.ForEach(pp=> Entry(pp).State=EntityState.Deleted);
return base.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)
这样您就可以避免调用该Find方法.
| 归档时间: |
|
| 查看次数: |
1206 次 |
| 最近记录: |