我有实体Project
和Sprint
,其中Sprint属于项目。项目还包含Backlog
,它是对默认情况下将添加项目的单个Sprint的引用。
public class Project
{
public long ID { get; set; }
public string Name { get; set; }
public long BacklogId { get; set; }
public Sprint Backlog { get; set; }
}
public class Sprint
{
public long ID { get; set; }
public string Name { get; set; }
public long ProjectId { get; set; }
public Project Project { get; set; }
}
实体框架显然无法从上面确定这两个实体之间的关系并抛出
其他信息:无法确定类型' Sprint'之间关联的主要目标。和'项目'。必须使用关系流畅API或数据注释显式配置此关联的主要结尾。
我经常试错,无法通过各种问题,例如'多重性在角色中无效。的问题。
如何使用数据注释或OnModelCreating()
正确描述这种关系。我目前有
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Sprint>()
.HasRequired(x => x.Project)
.WithRequiredPrincipal(x => x.Backlog);
}
背景:我使用EF6并使用System.Data.SQLite.EF6
提供程序连接到Sqlite文件
答案 0 :(得分:2)
我认为你实际上需要两种不同的关系。项目和sprint之间有1:0..N(项目的所有冲刺),项目和sprint之间的0..1:1(项目的积压冲刺),所以你需要两个模型构建器声明。 Sprint.ProjectId
是第一个关联的FK,Project.BacklogId
是第二个关联。当然,这种布局允许您指定不属于项目的待办事项,因此您需要对其进行验证。或者,您可以引入Sprint.IsBacklog
标志,在这种情况下,您只需要一个关联。
答案 1 :(得分:2)
以下OnModelCreating()
有效并且看似正确。
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Sprint>()
.HasKey(s => s.ID)
.HasRequired(s => s.Project)
.WithMany(p => p.Sprints)
.HasForeignKey(s => s.ProjectId);
modelBuilder.Entity<Project>()
.HasKey(p => p.ID)
.HasOptional(p => p.Backlog);
}
使用HasOptional
使用modelBuilder
并使用Project.BacklogId
使long?
可空,将Backlog设置为可选项非常重要。否则有循环引用,我们将无法创建任何实体。将Backlog引用保留在Project(因为它属于Project)而不是在Sprint上创建IsBacklog
是有意义的。
额外引用Project
的{{1}} 集合 - 感谢@fejesjoco和@Zakos指出
Sprint
即使public class Project
{
public long ID { get; set; }
public string Name { get; set; }
public ICollection<Sprint> Sprints { get; set; } // new
public long? BacklogId { get; set; } // changed
public Sprint Backlog { get; set; }
}
public class Sprint
{
public long ID { get; set; }
public string Name { get; set; }
public long ProjectId { get; set; }
public Project Project { get; set; }
}
可以为空,实体框架也会将此视为循环引用并抛出 DbUpdateException :
无法确定相关操作的有效排序。由于外键约束,模型要求或存储生成的值,可能存在依赖关系。
事实证明,2012年底报告的EF错误/想法列表上有ticket #142,但问题完全相同。目前的状态已经提出,EF代表发表评论说:
我们同意这是一个很好的启用方案。考虑到我们在EF6版本中的位置以及此功能的大小和影响,我们的团队不打算在EF6中实现它。因此,我们正在将其转移到Future版本,以便在下一版本中重新考虑。
- RoMiller于2013年1月25日上午9:17写道
解决这个问题的方法是在事务中保存两次上下文
Project.BacklogId
答案 2 :(得分:0)
这可用于EF Core。
public class Project
{
public long ID { get; set; }
public string Name { get; set; }
// explicit constraint is required to resolve child-dependent relationship
[ForeignKey("BacklogId")]
public virtual Sprint Backlog { get; set; }
}
public class Sprint
{
public long ID { get; set; }
public string Name { get; set; }
// explicit constraint is required to resolve child-dependent relationship
[ForeignKey("ProjectId")]
public virtual Project Project { get; set; }
}
var project = new Project { Name = "Some project" };
// intermediate saving is required to avoid circular dependency exception
context.Projects.Add(project);
context.SaveChanges();
var backlog = new Sprint { Name = "Backlog sprint", Project = project };
project.Backlog = backlog;
context.Sprints.Add(backlog);
context.SaveChanges();