实体框架多对多关系表创建“向后”

时间:2021-10-18 07:42:05

I'm having an issue with EF6 and many-to-many relations. I have a following setup:

我遇到了EF6和多对多关系的问题。我有以下设置:

public class Foo
{
    public int Id { get; set; }
    public virtual ICollection<Bar> Bars { get; set; }
    public virtual ICollection<SubBar> SubBars { get; set; }

    public Foo()
    {
        Bars = new HashSet<Bar>();
        SubBars = new HashSet<SubBar>();
    }
}

public class Bar
{
    public int Id { get; set; }
    public virtual ICollection<Foo> Foos { get; set; }

    public Bar()
    {
        Foos = new HashSet<Foo>();
    }
}

public class SubBar
{
    public int Id { get; set; }
    public virtual ICollection<Foo> Foos { get; set; }

    public SubBar()
    {
        Foos = new HashSet<Foo>();
    }
}

The relation between Foo and Bar works properly, and there is a table called BarFoos in the DB. However the relation between Foo and SubBar is reversed. There is a table in the DB called FooSubBars which basically holds the correct relations, but eager loading, like SubBar.AsQueryable().Include(sb => sb.Foos) returns an EntityCommandExecutionException with a message Invalid object name dbo.SubBarFoos.

Foo和Bar之间的关系正常工作,DB中有一个名为BarFoos的表。然而,Foo和SubBar之间的关系是相反的。数据库中有一个名为FooSubBars的表,它基本上保持正确的关系,但是像SubBar.AsQueryable()一样急切加载.Include(sb => sb.Foos)返回一个EntityCommandExecutionException,其中包含一个消息Invalid object name dbo.SubBarFoos。

Question is: How do I reverse the relation table name to allow eager loading?
--Edit--
DB creation in the migration is as follows:

问题是:如何反转关系表名称以允许急切加载? --Edit--迁移中的数据库创建如下:

CreateTable(
            "dbo.BarFoos",
            c => new
                {
                    Bar_Id = c.Int(nullable: false),
                    Foo_Id = c.Int(nullable: false),
                })
            .PrimaryKey(t => new { t.Bar_Id, t.Foo_Id })
            .ForeignKey("dbo.Bars", t => t.Bar_Id, cascadeDelete: true)
            .ForeignKey("dbo.Foos", t => t.Foo_Id, cascadeDelete: true)
            .Index(t => t.Bar_Id)
            .Index(t => t.Foo_Id);

CreateTable(
            "dbo.FooSubBars",
            c => new
                {
                    Foo_Id = c.Int(nullable: false),
                    SubBar_Id = c.Int(nullable: false),
                })
            .PrimaryKey(t => new { t.Foo_Id, t.SubBar_Id })
            .ForeignKey("dbo.Foos", t => t.Foo_Id, cascadeDelete: true)
            .ForeignKey("dbo.SubBars", t => t.SubBar_Id, cascadeDelete: true)
            .Index(t => t.Foo_Id)
            .Index(t => t.SubBar_Id);

Would replacing the table name in the migration be sufficient?

在迁移中替换表名是否足够?

2 个解决方案

#1


You can ensure the table name is generated as "FooBars" if you override the OnModelCreating method on your DbContext as follows:

如果您在DbContext上覆盖OnModelCreating方法,则可以确保将表名生成为“FooBars”,如下所示:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<Foo>().HasMany(f => f.Bars).WithMany(b => b.Foos)
            .Map(m => 
                m.ToTable("FooBars")
                // Optionally specify the key column names...
                .MapLeftKey("FooId") 
                .MapRightKey("BarId")
            );

    modelBuilder.Entity<Foo>().HasMany(f => f.SubBars).WithMany(sb => sb.Foos).Map(m => m.ToTable("FooSubBars"));
}

Which will produce this in the migration:

这将在迁移中产生这种情况:

        CreateTable(
            "dbo.FooBar",
            c => new
                {
                    FooId = c.Int(nullable: false),
                    BarId = c.Int(nullable: false),
                })
            .PrimaryKey(t => new { t.FooId, t.BarId })
            .ForeignKey("dbo.Foos", t => t.FooId, cascadeDelete: true)
            .ForeignKey("dbo.Bars", t => t.BarId, cascadeDelete: true)
            .Index(t => t.FooId)
            .Index(t => t.BarId);

        CreateTable(
            "dbo.FooSubBar",
            c => new
                {
                    Foo_Id = c.Int(nullable: false),
                    SubBar_Id = c.Int(nullable: false),
                })
            .PrimaryKey(t => new { t.Foo_Id, t.SubBar_Id })
            .ForeignKey("dbo.Foos", t => t.Foo_Id, cascadeDelete: true)
            .ForeignKey("dbo.SubBars", t => t.SubBar_Id, cascadeDelete: true)
            .Index(t => t.Foo_Id)
            .Index(t => t.SubBar_Id);

I also tried eager loading the Foos when querying SubBars on the DbContext with don't get any errors:

我也尝试在DbContext上查询SubBars时急切加载Foos,不要出现任何错误:

var context = new FooBarContext();

var subBars = from sb in context.SubBars.Include(i => i.Foos)
              select sb;

#2


I was able to reverse the naming by checking here

我可以通过在这里查看来反转命名

https://msdn.microsoft.com/en-us/library/jj591620(v=vs.113).aspx

So long as both Entity1 and Entity2 have navagational properties to eachother, then the following works.

只要Entity1和Entity2都具有彼此的导航属性,那么以下工作。

            modelBuilder.Entity<Order>()
                .HasMany(t => t.Products)
                .WithMany(t => t.Orders);

which produces

            CreateTable(
            "dbo.OrderProducts",
            c => new
                {
                    Order_OrderID = c.Int(nullable: false),
                    Product_ID = c.Int(nullable: false),
                })
            .PrimaryKey(t => new { t.Order_OrderID, t.Product_ID })
            .ForeignKey("dbo.Orders", t => t.Order_OrderID, cascadeDelete: true)
            .ForeignKey("dbo.Products", t => t.Product_ID, cascadeDelete: true)
            .Index(t => t.Order_OrderID)
            .Index(t => t.Product_ID);

#1


You can ensure the table name is generated as "FooBars" if you override the OnModelCreating method on your DbContext as follows:

如果您在DbContext上覆盖OnModelCreating方法,则可以确保将表名生成为“FooBars”,如下所示:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<Foo>().HasMany(f => f.Bars).WithMany(b => b.Foos)
            .Map(m => 
                m.ToTable("FooBars")
                // Optionally specify the key column names...
                .MapLeftKey("FooId") 
                .MapRightKey("BarId")
            );

    modelBuilder.Entity<Foo>().HasMany(f => f.SubBars).WithMany(sb => sb.Foos).Map(m => m.ToTable("FooSubBars"));
}

Which will produce this in the migration:

这将在迁移中产生这种情况:

        CreateTable(
            "dbo.FooBar",
            c => new
                {
                    FooId = c.Int(nullable: false),
                    BarId = c.Int(nullable: false),
                })
            .PrimaryKey(t => new { t.FooId, t.BarId })
            .ForeignKey("dbo.Foos", t => t.FooId, cascadeDelete: true)
            .ForeignKey("dbo.Bars", t => t.BarId, cascadeDelete: true)
            .Index(t => t.FooId)
            .Index(t => t.BarId);

        CreateTable(
            "dbo.FooSubBar",
            c => new
                {
                    Foo_Id = c.Int(nullable: false),
                    SubBar_Id = c.Int(nullable: false),
                })
            .PrimaryKey(t => new { t.Foo_Id, t.SubBar_Id })
            .ForeignKey("dbo.Foos", t => t.Foo_Id, cascadeDelete: true)
            .ForeignKey("dbo.SubBars", t => t.SubBar_Id, cascadeDelete: true)
            .Index(t => t.Foo_Id)
            .Index(t => t.SubBar_Id);

I also tried eager loading the Foos when querying SubBars on the DbContext with don't get any errors:

我也尝试在DbContext上查询SubBars时急切加载Foos,不要出现任何错误:

var context = new FooBarContext();

var subBars = from sb in context.SubBars.Include(i => i.Foos)
              select sb;

#2


I was able to reverse the naming by checking here

我可以通过在这里查看来反转命名

https://msdn.microsoft.com/en-us/library/jj591620(v=vs.113).aspx

So long as both Entity1 and Entity2 have navagational properties to eachother, then the following works.

只要Entity1和Entity2都具有彼此的导航属性,那么以下工作。

            modelBuilder.Entity<Order>()
                .HasMany(t => t.Products)
                .WithMany(t => t.Orders);

which produces

            CreateTable(
            "dbo.OrderProducts",
            c => new
                {
                    Order_OrderID = c.Int(nullable: false),
                    Product_ID = c.Int(nullable: false),
                })
            .PrimaryKey(t => new { t.Order_OrderID, t.Product_ID })
            .ForeignKey("dbo.Orders", t => t.Order_OrderID, cascadeDelete: true)
            .ForeignKey("dbo.Products", t => t.Product_ID, cascadeDelete: true)
            .Index(t => t.Order_OrderID)
            .Index(t => t.Product_ID);