简体   繁体   English

编写第一个实体框架(EF6)的代码,在初始创建后添加多对多关系

[英]Code first Entity Framework (EF6) Adding Many-to-Many relationship after initial create

I am new to MVC, the Entity Framework, and Databases in general, but I have not been able to figure out what is going on here. 我是MVC,实体框架和数据库的新手,但我无法弄清楚这里发生了什么。 I am trying to create a many-to-many relationship via code from an already created db. 我试图通过已经创建的数据库中的代码创建多对多关系。 Thanks in advance for any pointers you can give. 在此先感谢您提供的任何提示。

I have a code-first database defined by 2 models (the real one is much more complex, but for brevity this also shows my question/problem): 我有一个由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; }
}

When I run the Enable-Migrations -ContextTypeName ManyToManyTest.Models.ManyToManyDB, everything is fine. 当我运行Enable-Migrations -ContextTypeName ManyToManyTest.Models.ManyToManyDB时,一切都很好。 I get the Configuration.cs file in my project. 我在项目中获得Configuration.cs文件。 I do some editing there: 我在那里做一些编辑:

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

Add some data to the Seed method: 将一些数据添加到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" }
            );

Now I run "Update-Database -verbose" and the DB is created. 现在,我运行“ Update-Database -verbose”,并创建了数据库。 So far so good. 到现在为止还挺好。

Now lets say I forgot to create my Many to Many relationship in the Company class, so I update it: 现在说我忘了在Company类中创建多对多关系,因此我对其进行了更新:

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
}

Ok, so, as this is early on in development, I should be able to just run "update-database" again and it will add the necessary stuff (which in this case will include a new junction table for the many-to-many relationship). 好的,所以,因为这是开发的早期阶段,所以我应该能够再次运行“ update-database”,它将添加必要的内容(在这种情况下,它将包括一个用于多对多的新联结表关系)。 Unfortunately, when I do, this happens: 不幸的是,当我这样做时,会发生:

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

Caution: Changing any part of an object name could break scripts and stored procedures. 警告:更改对象名称的任何部分都可能会破坏脚本和存储过程。

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]

It throws this exception 引发此异常

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

The error being: Cannot find the object "dbo.Companies" because it does not exist or you do not have permissions. 错误为:找不到对象“ dbo.Companies”,因为该对象不存在或您没有权限。

Any idea why I cannot create a many-to-many relationship after creating the initial db schema? 知道为什么在创建初始数据库模式后无法创建多对多关系吗?

I may just try again from the start, but wanted to know if there is a solution to this in case I happen upon it in the future. 我可能只是从头开始尝试,但是想知道是否有解决方案,以防将来发生这种情况。

Using VS2013 and EF6.02 if that matters. 如果重要的话,请使用VS2013和EF6.02。 The project is from the normal MVC template. 该项目来自普通的MVC模板。

Sorry to say but it seems like a bug in EF. 抱歉地说,但这似乎是EF中的错误。 EF generates automatic update that is equal to the one that would be produced by running Add-Migration. EF生成的自动更新与运行“添加迁移”所产生的更新相同。

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

Now in the second line of migration method it calls DropForeignKey that produces ALTER TABLE with DROP that ends with an exception because table was renamed in the first place. 现在,在迁移方法的第二行中,它调用DropForeignKey,它产生带有DROP的ALTER TABLE并以异常结尾,因为表是首先被重命名的。

The workaround is to run Add-Migration, drop code and write it by hand. 解决方法是运行Add-Migration,删除代码并手动编写。 I ended up with code like this: 我最终得到了这样的代码:

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

Answering my own question. 回答我自己的问题。 After a few hours of thinking about it, like pg0xC states it is probably a bug in the Entity Framework. 经过数小时的思考,就像pg0xC指出的那样,它可能是实体框架中的错误。 Here is an easy workaround in case anyone else hits this problem. 如果其他人遇到此问题,这是一个简单的解决方法。

Sticking with my example above, remove both of the ICollections from the Beer and Company classes: 继续上面的示例,从Beer和Company类中删除这两个ICollection:

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
}

Now run update-database again... it worked for me on both the sample as well as my actual code. 现在再次运行update-database ...它对示例和实际代码都有效。 Of course you will lose any Companies that were linked to the beer class. 当然,您将失去与啤酒相关的任何公司。 If this is unacceptable, you will have to do something similar to what the other answerer (pg0xC) stated. 如果这是不可接受的,则您将必须执行与其他应答程序(pg0xC)所述类似的操作。

Go back and uncomment the ICollections in both the Beer and Company classes, run update-database one last time and everything should work. 返回并取消对Beer和Company类中的ICollection的注释,最后一次运行update-database,一切都应该正常工作。 After doing this, I had the CompanyBeers junction table in the localdb. 完成此操作后,我在localdb中有了CompanyBeers联结表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM