首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >实体框架6代码中相互引用的两个表

实体框架6代码中相互引用的两个表
EN

Stack Overflow用户
提问于 2014-11-23 10:42:52
回答 3查看 2.5K关注 0票数 2

我有实体ProjectSprint,其中Sprint属于一个项目。项目还包含一个Backlog,它是对单个Sprint的引用,默认情况下它将向其中添加项。

代码语言:javascript
复制
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‘和'Project’之间关联的主端。必须使用关系fluent API或数据注释显式地配置此关联的主体端。

我已经尝试了很多,无法通过各种问题,比如“多重性在角色中无效”等问题。

如何正确地使用数据注释或OnModelCreating()正确地建模我所描述的这种关系。我现在有

代码语言:javascript
复制
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Sprint>()
        .HasRequired(x => x.Project)
        .WithRequiredPrincipal(x => x.Backlog);
}

背景:我正在使用EF6,并使用System.Data.SQLite.EF6提供程序连接到Sqlite文件

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-11-24 09:23:58

下面的OnModelCreating()起作用了,而且看起来是正确的。

代码语言:javascript
复制
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将积压设置为可选,并使用long?使Project.BacklogId为空是很重要的。否则会有一个循环引用,我们将无法创建任何一个实体。保留项目上的待定引用(因为它属于项目)是有意义的,而不是在Sprint上创建IsBacklog

ProjectSprint集合的附加引用-感谢https://stackoverflow.com/a/27088107/80428https://stackoverflow.com/a/27090274/80428指出这一点。

代码语言:javascript
复制
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; }
}

重要注记

尽管Project.BacklogId是可空的,实体框架将其视为循环引用,并抛出一个DbUpdateException

无法确定从属操作的有效排序。依赖项可能由于外键约束、模型需求或存储生成的值而存在。

事实证明,2012年末,EF的bug/idea列表中出现了票#142,其问题与此完全相同。它的现状是提出的,并有一名EF代表评论说:

我们同意,这将是一个很好的设想。考虑到我们在EF6发行版中的位置,以及这个特性的大小和影响,我们的团队没有计划在EF6中实现它。因此,我们正在将其转移到未来版本,以便在下一个版本中重新考虑。 - RoMiller于2013年1月25日上午9:17写信

解决办法

克服这一问题的方法是在事务中保存两次上下文。

代码语言:javascript
复制
using (var transaction = context.Database.BeginTransaction())
{
    try
    {
        var project = new Project { Name = "Project 1" };
        context.Projects.Add(project);
        context.SaveChanges();

        var backlog = new Sprint { Name = "Backlog", Project = project };
        project.Backlog = backlog;
        context.Sprints.Add(backlog);
        context.SaveChanges();

        transaction.Commit();
    }
    catch (Exception)
    {
        transaction.Rollback();
        throw;
    }
}
票数 2
EN

Stack Overflow用户

发布于 2014-11-23 10:49:27

我觉得你真的需要两种截然不同的关系。在项目和sprint之间有一个1:0..N (项目的所有sprint ),在项目和sprint之间有0.1:1(项目的待办冲刺),所以您需要两个模型生成器语句。Sprint.ProjectId是第一个协会的FK,Project.BacklogId是第二个。当然,这个布局允许您指定一个不属于项目的待办事项,所以需要对其进行验证。或者,您可以引入一个Sprint.IsBacklog标志,在这种情况下,您只需要一个关联。

票数 2
EN

Stack Overflow用户

发布于 2019-06-18 06:59:40

这适用于EF核心。

代码语言:javascript
复制
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();
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27088054

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档