代码优先实体框架(EF6)在初始创建后添加多对多关系

时间:2014-01-30 14:13:32

标签: c# database entity-framework

我是MVC,实体框架和数据库的新手,但我还没弄清楚这里发生了什么。我试图通过已创建的数据库中的代码创建多对多关系。提前感谢您提供的任何指示。

我有一个由2个模型定义的代码优先数据库(真正的数据库要复杂得多,但为了简洁,这也显示了我的问题/问题):

public class Beer
{
    public int BeerID { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Company> Companies { get; set; }  // one beer could have many companies

}

public class Company
{
    public int CompanyID { get; set; }
    public string Name { get; set; }

    // Navigation Property

}

public class ManyToManyDB : DbContext
{
    public DbSet<Beer> Beers { get; set; }
    public DbSet<Company> Companies { get; set; }
}

当我运行Enable-Migrations -ContextTypeName ManyToManyTest.Models.ManyToManyDB时,一切都很好。我在项目中获得了Configuration.cs文件。我在那里做了一些编辑:

    public Configuration()
    {
        AutomaticMigrationsEnabled = true;
        AutomaticMigrationDataLossAllowed = true;
    }

向Seed方法添加一些数据:

        context.Companies.AddOrUpdate(c => c.Name,
            new Company { Name = "Company1" },
            new Company { Name = "Company2" },
            new Company { Name = "Company3" }
            );

        context.Beers.AddOrUpdate(b => b.Name,
            new Beer { Name = "Beer1" },
            new Beer { Name = "Beer2" },
            new Beer { Name = "Beer3" }
            );

现在我运行“Update-Database -verbose”并创建数据库。到目前为止一切都很好。

现在假设我忘了在公司课程中创建我的多对多关系,所以我更新它:

public class Company
{
    public int CompanyID { get; set; }
    public string Name { get; set; }

    // Navigation Property
    public virtual ICollection<Beer> Beers { get; set; }  // this is what I forgot, a company can have many beers
}

好的,所以,因为这是在开发的早期,我应该能够再次运行“update-database”,它将添加必要的东西(在这种情况下将包括一个新的连接表,用于许多 - 多对多的关系)。不幸的是,当我这样做时,会发生这种情况:

EXECUTE sp_rename @objname = N'dbo.Companies', @newname = N'CompanyBeers', @objtype = N'OBJECT'

警告:更改对象名称的任何部分可能会破坏脚本和存储过程。

IF object_id(N'[dbo].[FK_dbo.Companies_dbo.Beers_Beer_BeerID]', N'F') IS NOT NULL
    ALTER TABLE [dbo].[Companies] DROP CONSTRAINT [FK_dbo.Companies_dbo.Beers_Beer_BeerID]

抛出此异常

System.Data.SqlClient.SqlException (0x80131904): Cannot find the object "dbo.Companies" because it does not exist or you do not have permissions.

错误是: 找不到对象“dbo.Companies”,因为它不存在或者您没有权限。

知道在创建初始数据库模式后我无法创建多对多关系的原因吗?

我可能只是从一开始就再试一次,但想知道是否有解决方案,以防将来发生。

如果重要,请使用VS2013和EF6.02。该项目来自正常的MVC模板。

2 个答案:

答案 0 :(得分:1)

很抱歉,但这似乎是EF中的一个错误。 EF生成的自动更新等于通过运行Add-Migration生成的更新。

    public override void Up()
    {
        RenameTable(name: "dbo.Companies", newName: "CompanyBeers");
        DropForeignKey("dbo.Companies", "Beer_BeerID", "dbo.Beers");
        DropIndex("dbo.Companies", new[] { "Beer_BeerID" });
        CreateIndex("dbo.CompanyBeers", "Company_CompanyID");
        CreateIndex("dbo.CompanyBeers", "Beer_BeerID");
        AddForeignKey("dbo.CompanyBeers", "Company_CompanyID", "dbo.Companies", "CompanyID", cascadeDelete: true);
        AddForeignKey("dbo.CompanyBeers", "Beer_BeerID", "dbo.Beers", "BeerID", cascadeDelete: true);
        DropColumn("dbo.Companies", "Beer_BeerID");
    }

现在在第二行迁移方法中,它调用DropForeignKey生成带有DROP的ALTER TABLE,该DROP以异常结束,因为表首先被重命名。

解决方法是运行Add-Migration,删除代码并手动编写。我最终得到了这样的代码:

    public override void Up()
    {
        DropIndex("dbo.Companies", new[] { "Beer_BeerID" });
        DropForeignKey("dbo.Companies", "Beer_BeerID", "dbo.Beers");
        DropColumn("dbo.Companies", "Beer_BeerID");

        CreateTable(
            "dbo.CompanyBeers",
            c => new
            {
                Company_CompanyID = c.Int(nullable: false),
                Beer_BeerID = c.Int(nullable: false),
            })
            .PrimaryKey(t => new { t.Company_CompanyID, t.Beer_BeerID })
            .ForeignKey("dbo.Companies", t => t.Company_CompanyID, cascadeDelete: true)
            .ForeignKey("dbo.Beers", t => t.Beer_BeerID, cascadeDelete: true)
            .Index(t => t.Company_CompanyID)
            .Index(t => t.Beer_BeerID);
    }

答案 1 :(得分:0)

回答我自己的问题。经过几个小时的思考后,像pg0xC一样,它可能是实体框架中的一个错误。如果其他人遇到此问题,这是一个简单的解决方法。

坚持上面的示例,从Beer和Company类中删除两个ICollections:

public class Beer
{
    public int BeerID { get; set; }
    public string Name { get; set; }
    //public virtual ICollection<Company> Companies { get; set; }  // one beer could have many companies

}

public class Company
{
    public int CompanyID { get; set; }
    public string Name { get; set; }

    // Navigation Property
    // public virtual ICollection<Beer> Beers { get; set; }  // this is what I forgot, a co
}

现在再次运行update-database ...它既适用于我的样本,也适用于我的实际代码。当然,您将失去任何与啤酒类相关的公司。如果这是不可接受的,你将不得不做一些与其他回答者(pg0xC)所说的相似的事情。

返回并取消注释Beer和Company类中的ICollections,最后一次运行update-database,一切都应该有效。执行此操作后,我在localdb中有了CompanyBeers联结表。