使用Code First迁移添加外键 [英] adding a foreign key with Code First migration
问题描述
这是我在添加迁移之前的类
public class Product b $ b {
public Product(){}
$ b public int ProductId {get;组; }
public string Name {get;组; }
public decimal Price {get;组; }
public bool Istaxable {get;组; }
public string DefaultImage {get;组; }
public IList< Feature>特点{get;组; }
public IList< Descriptor>描述符{get;组; }
public IList< Image>图片{get;组; }
public IList< Category>分类{get;组; }
}
public class Feature
{
public int Id {get;组; }
public string Title {get;组; }
public string描述{get;组; }
现在我想在我的特性中添加一个外键类和重构类:
public class Product
{
public Product(){}
public int ProductId {get;组; }
public string Name {get;组; }
public decimal Price {get;组; }
public bool Istaxable {get;组; }
public string DefaultImage {get;组; }
public IList< Feature>特点{get;组; }
public IList< Descriptor>描述符{get;组; }
public IList< Image>图片{get;组; }
public IList< Category>分类{get;组; }
}
public class Feature
{
public int Id {get;组; }
public string Title {get;组; }
public string描述{get;组; }
public string Image {get;组; }
公共字符串VideoLink {get;组; }
public int ProductId {get;组; }
public Product Product {get;组; }
$我添加了一个迁移 Add-Migration
命令。
我添加了一个 Update-Database
命令,这里是我回来的:
lockquote
ALTER TABLE语句与FOREIGN KEY约束
FK_dbo.ProductFeatures_dbo.Products_ProductId冲突。数据库CBL,表dbo.Products,ProductId列中发生冲突
做解决这个问题,并让我的迁移恢复正常?
解决方案
解决这个问题的关键是打破你的迁移到两次迁移。首先,添加一个可为空的字段并填写数据。第二,使该字段成为必需的外键。
第一迁移
-
将这个新的属性作为一个可为空的类型(例如int?)添加到你的类中。
$ b $ pre $ public $ MyOtherEntity
{
public int Id {get;组; }
}
public class MyEntity
{
...
//对MyOtherEntity的新引用
public int? MyOtherEntityId {get;组; }
...
}
-
创建迁移。注意:迁移名称并不重要,但是像AddBlogPosts1这样的内容可以很容易阅读。
> add-migration AddMyEntityMyOtherEntity1
-
这应该支持如下的迁移:
public partial class AddMyTableNewProperty1:DbMigration
{
public override void Up()
{
AddColumn(dbo.MyEntity,MyOtherEntityId,c => c.Int());
public override void Down()
{
DropColumn(dbo.MyEntity,MyOtherEntityId);
$现在手动编辑生成的迁移以添加新字段的默认值。最简单的情况是默认值是不变的。如果需要,您可以在SQL中添加更多的逻辑。这个例子假设所有的MyEntity实例指向ID为1的MyOtherEntity实例。
$ b $ pre $ b {
public override void Up()
{
AddColumn(dbo.MyEntity,MyOtherEntityId,c => c.Int());
//把这个加到
Sql(@UPDATE dbo.MyEntity SET MyOtherEntityId = 1
where MyOtherEntity IS NULL);
public override void Down()
{
DropColumn(dbo.MyEntity,MyOtherEntityId);
$ li $更新数据库
> update-database
-
返回MyEntity类并更改新属性以表示强制外键。
public class MyEntity
{
...
//更改int?为了使它强制
public int MyOtherEntityId {get;组; }
//创建对其他实体的引用
public virtual MyOtherEntity MyOtherEntity {get;组; }
...
}
-
p>
> add-migration AddMyEntityMyOtherEntity2
-
这应该创建如下的迁移: b
$ bpublic partial class AddMyEntityMyOtherEntity2:DbMigration
{
public override void Up()
{
AlterColumn (dbo.MyEntity,MyOtherEntityId,c => c.Int(nullable:false));
CreateIndex(dbo.MyEntity,MyOtherEntityId);
AddForeignKey(dbo.MyEntity,MyOtherEntityId,dbo.MyOtherEntity,Id);
public override void Down()
{
DropForeignKey(dbo.MyEntity,MyOtherEntityId,dbo.MyOtherEntity);
DropIndex(dbo.MyEntity,new [] {MyOtherEntityId});
AlterColumn(dbo.MyEntity,MyOtherEntityId,c => c.Int());
$ li $更新数据库
> update-database
- 此技术适用于在应用程序启动时应用的迁移。
- 添加更复杂的映射SQL是可能的,但这里没有说明。
Add the new property to your class as a nullable type (e.g. int?)
public class MyOtherEntity { public int Id { get; set; } } public class MyEntity { ... // New reference to MyOtherEntity public int? MyOtherEntityId { get; set; } ... }
Create a migration. NOTE: Migration name is not important, but something like "AddBlogPosts1" makes it easy to read.
> add-migration AddMyEntityMyOtherEntity1
This should scaffold a migration that looks like this:
public partial class AddMyTableNewProperty1 : DbMigration { public override void Up() { AddColumn("dbo.MyEntity", "MyOtherEntityId", c => c.Int()); } public override void Down() { DropColumn("dbo.MyEntity", "MyOtherEntityId"); } }
Now manually edit the generated migration to add a default value for the new field. The easiest case is when the default value is invariant. You can add more logic in the SQL if needed. This example assumed all the MyEntity instances point to the same MyOtherEntity instance with ID 1.
public partial class AddMyTableNewProperty1 : DbMigration { public override void Up() { AddColumn("dbo.MyEntity", "MyOtherEntityId", c => c.Int()); // ADD THIS BY HAND Sql(@"UPDATE dbo.MyEntity SET MyOtherEntityId = 1 where MyOtherEntity IS NULL"); } public override void Down() { DropColumn("dbo.MyEntity", "MyOtherEntityId"); } }
Update the database
> update-database
Go back to your MyEntity class and change the new property to represent a mandatory foreign key.
public class MyEntity { ... // Change the int? to int to make it mandatory public int MyOtherEntityId { get; set; } // Create a reference to the other entity public virtual MyOtherEntity MyOtherEntity { get; set; } ... }
Create another migration
> add-migration AddMyEntityMyOtherEntity2
This should create a migration like the following:
public partial class AddMyEntityMyOtherEntity2: DbMigration { public override void Up() { AlterColumn("dbo.MyEntity", "MyOtherEntityId", c => c.Int(nullable: false)); CreateIndex("dbo.MyEntity", "MyOtherEntityId"); AddForeignKey("dbo.MyEntity", "MyOtherEntityId", "dbo.MyOtherEntity", "Id"); } public override void Down() { DropForeignKey("dbo.MyEntity", "MyOtherEntityId", "dbo.MyOtherEntity"); DropIndex("dbo.MyEntity", new[] { "MyOtherEntityId" }); AlterColumn("dbo.MyEntity", "MyOtherEntityId", c => c.Int()); } }
Update the database
> update-database
- This technique works for migrations applied during application start up.
- Adding more complex mappings for the new column in the SQL are possible, but not illustrated here.
第二迁移
$ b
其他注意事项
I have an error when trying to update my database after adding a migration.
Here are my classes before add-migration
public class Product
{
public Product() { }
public int ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public bool Istaxable { get; set; }
public string DefaultImage { get; set; }
public IList<Feature> Features { get; set; }
public IList<Descriptor> Descriptors { get; set; }
public IList<Image> Images { get; set; }
public IList<Category> Categories { get; set; }
}
public class Feature
{
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
}
Now I wanted to add a foreign key in my Feature class and refactored the classes this way:
public class Product
{
public Product() { }
public int ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public bool Istaxable { get; set; }
public string DefaultImage { get; set; }
public IList<Feature> Features { get; set; }
public IList<Descriptor> Descriptors { get; set; }
public IList<Image> Images { get; set; }
public IList<Category> Categories { get; set; }
}
public class Feature
{
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Image { get; set; }
public string VideoLink { get; set; }
public int ProductId { get; set; }
public Product Product { get; set; }
}
I added a migration with Add-Migration
command.
I added an Update-Database
command and here is what I got back:
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_dbo.ProductFeatures_dbo.Products_ProductId". The conflict occurred in database "CBL", table "dbo.Products", column 'ProductId'
What can I do to solve this problem and get my migrations back to normal?
The key to solving this problem is to break your migration into two migrations. First, add a nullable field and fill in the data. Second, make the field a required foreign key.
First Migration
Second Migration
Other Notes
这篇关于使用Code First迁移添加外键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!