实体框架6中的两个表引用代码第一 [英] Two tables referencing each other in Entity Framework 6 Code First

查看:273
本文介绍了实体框架6中的两个表引用代码第一的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有Sprint属于项目的实体 Project Sprint 项目还包含一个 Backlog ,它是对单个Sprint的引用,它将默认添加项目。

I have the entities Project and Sprint where a Sprint belongs to a Project. A Project also contains a Backlog which is a reference to a single Sprint it will add items to by default.

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; }
}

实体框架显然无法确定这两个实体之间的关系,以上和抛出

Entity Framework obviously can't determine the relationship between these two entities just from the above and throw


附加信息:无法确定类型Sprint和Project之间的关联的主要结束。必须使用流畅的API或数据注释来明确配置此关联的主体。

Additional information: Unable to determine the principal end of an association between the types 'Sprint' and 'Project'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.

我已经尝试 - 错误很多,不能通过各种问题,如多重性在角色问题中无效。

I've been trial-and-erroring a lot and cannot get passed various issues such as 'Multiplicity is not valid in Role' issues.

如何正确地建模我已经正确描述的关系数据注释或 OnModelCreating()。我现在有

How do correctly I model this relationship I've described correctly using either Data Annotations or OnModelCreating(). I currently have

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Sprint>()
        .HasRequired(x => x.Project)
        .WithRequiredPrincipal(x => x.Backlog);
}

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

推荐答案

p>以下 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设置Backlog是非常重要的使用 modelBuilder 并使 Project.BacklogId 可空,使用 long? 。否则有循环引用,我们将无法创建任何一个实体。在项目(属于项目)中保留Backlog参考是有意义的,而不是在Sprint上创建一个 IsBacklog

It was important to set Backlog as optional using HasOptional using modelBuilder and making Project.BacklogId nullable with long?. otherwise there's a circular reference and we won't be able to create either entity. It made sense to keep the Backlog reference on Project (as it belongs to the Project) instead of creating an IsBacklog on Sprint.

附加参考 Project 收集 Sprint - 感谢 @fejesjoco @Zakos 指出这一点

With the additional reference to Project's collection of Sprint - thanks to @fejesjoco and @Zakos for pointing this out

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

Important Note

Even though Project.BacklogId is nullable, Entity Framework sees this as a circular reference and throws a DbUpdateException:


无法确定依赖操作的有效排序。由于外键约束,模型要求或存储生成值,可能存在依赖关系。

Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values.

事实证明,票#142 具有完全相同的问题。目前的状态被提出,并有一个EF的评论代表说:

As it turns out there's ticket #142 on EF's bug/idea list reported in late 2012 with exact same problem. It's current status is proposed and there's a comment by an EF rep saying:


我们同意这将是一个很好的场景启用。考虑到我们在EF6版本中的位置以及此功能的大小和影响,我们的团队并不打算在EF6中实施。因此,我们正在将其转移到未来版本,以便在下一个版本中重新考虑。

We agree that this would be a good scenario to enable. Taking into account where we are in the EF6 release along with the size and the impact of this feature our team is not planning to implement it in EF6. Therefore, we are moving it to the Future release to reconsider in the next release.

- RoMiller于2013年1月25日上午9:17发布>

- RoMiller wrote Jan 25, 2013 at 9:17 AM



解决方法



克服这个问题的方法是保存到在事务中的两次内容

Workaround

The way to overcome this is to save to the context twice inside a transaction

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;
    }
}

这篇关于实体框架6中的两个表引用代码第一的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆