EF 迁移正在删除一个列并尝试将一个不存在的列重命名回 Id
EF migration is dropping a column and trying to rename a nonexistent column back to Id
我有一个使用 EF 的代码优先 MVC 项目。
有两个表,TableA
和TableB
,它们目前是一对多的关系:
public partial class TableA
{
public TableA()
{
TableBs = new HashSet<TableB>();
}
public int Id { get; set; }
public Virtual ICollection<TableB> TableBs { get; set; }
}
public partial class TableB
{
public int Id { get; set; }
public int TableAId { get; set; }
public virtual TableA TableAs { get; set; }
}
modelBuilder.Entity<TableA>()
.HasMany(e => e.TableBs)
.WithRequired(e => e.TableA)
.HasForeignKey(e => e.TableAId);
我尝试更改 TableA
以赋予它一对零或一的关系:
public partial class TableA
{
public TableA() { }
public int Id { get; set; }
public int? TableBId { get; set; }
public virtual TableB TableB { get; set; }
}
TableB
保持不变,我像这样更改 OnModelCreating
:
modelBuilder.Entity<TableA>()
.HasOptional(e => e.TableBs);
modelBuilder.Entity<TableB>()
.HasRequired(e => e.TableAs);
问题是生成的迁移是意外的 -- 对我来说是意外的,因为我不知道我在做什么,很明显。它不是添加 FK 并添加列,而是尝试重命名列。这是我的迁移:
public override void Up()
{
DropForeignKey("dbo.TableA", "TableBId", "dbo.TableB");
DropIndex("dbo.TableA", new[] { "TableBId" });
DropColumn("dbo.TableB", "Id");
RenameColumn(table: "dbo.TableB", name: "TableBId", newName: "Id");
DropPrimaryKey("dbo.TableB");
AlterColumn("dbo.TableA", "TableBId", c => c.Int());
AlterColumn("dbo.TableB", "Id", c => c.Int(nullable: false));
AlterColumn("dbo.TableB", "TableAId", c => c.Int(nullable: false));
AddPrimaryKey("dbo.TableB", "Id");
CreateIndex("dbo.TableB", "Id");
}
我不明白为什么要重命名一个不存在的列以及我的新 FK 在哪里?
有几件事可能会导致您的问题:
流利的API通话描述关系
modelBuilder.Entity<TableA>()
.HasOptional(e => e.TableBs);
modelBuilder.Entity<TableB>()
.HasRequired(e => e.TableAs);
因为您在这里使用了两个引用不同属性的单独调用,所以我认为 EF 有可能将其解释为两个单独的关系。另一方面,由于它们都是一对一的,所以应该没问题。无论如何,它会更有意义:
modelBuilder.Entity<TableA>()
.HasOptional(e => e.TableBs)
.WithRequired(t => t.TableAs);
实体之间的任何一种一对一关系都需要两种实体类型共享一个主键(其中dependent/optional方的主键也是外键),即生成的迁移一团糟的主要原因。
我认为您也有可能尝试过 运行 过去在 dbo.TableA
中创建列 TableBId
的迁移。
根据jjj所说我的关系有严重的问题,我希望通过正常的迁移可以解决,但是jjj是正确的table依赖的FK和PK必须相同。我在 Azure 上使用 SQL 服务器 运行 所以我不能只删除列 TableB.Id
并将 TableB.TableAId
重命名为 TableB.Id
因为它给我一个聚集索引错误.他是对的,我的 down 语句没有下拉栏,所以我的 TableBId
仍在 dbo.TableA
。我回滚了我的数据库大约 5 次迁移。我对 TableA
的修改很好:
public partial class TableA
{
public int Id { get; set; }
public int? TableBId { get; set; }
public virtual TableB TableB { get; set; }
}
但问题出在 TableB
我不得不从模型中删除 TableAId
我在 sudo 代码中添加了列只是为了使迁移更具可读性:
public partial class TableB
{
public int Id { get; set; }
public int Column1 { get; set; }
public int Column2 { get; set; }
public int Column3 { get; set; }
public virtual TableA TableAs { get; set; }
}
现在在我的 DbContext 中,我使用了一个衬垫:
modelBuilder.Entity<TableB>()
.HasRequired(e => e.TableA).WithOptional(x => x.TableB);
当我添加迁移时,这是新创建的迁移:
public override void Up()
{
DropForeignKey("dbo.TableB", "TableAId", "dbo.TableAId");
DropIndex("dbo.TableB", new[] { "TableAId" });
DropColumn("dbo.TableB", "Id");
RenameColumn(table: "dbo.TableB", name: "TableAId", newName: "Id");
DropPrimaryKey("dbo.TableB");
AddColumn("dbo.Tenants", "TableBId", c => c.Int());
AlterColumn("dbo.TableB", "Id", c => c.Int(nullable: false));
AlterColumn("dbo.TableB", "Id", c => c.Int(nullable: false));
AddPrimaryKey("dbo.TableB", "Id");
CreateIndex("dbo.TableB", "Id");
AddForeignKey("dbo.TableB", "Id", "dbo.TableA", "Id");
}
这可能在其他版本的 SQL 中有效,但在 Azure 中无效,因为据我所知,它不允许堆 tables。所以这就是我更改迁移代码的方式。
public override void Up()
{
<-- I am renaming TableB to TableB_Old just for the migration-->
RenameTable(name: "dbo.TableB", newName: "TableB_Old");
DropForeignKey("dbo.TableB", "TableAId", "dbo.TableA");
DropIndex("dbo.TableB_Old", new[] { "TableAId" });
AlterColumn("dbo.TableB_Old", "TableAId", c => c.Int(nullable: false));
<-- Create a new TableB with the correct layout notice TableAId is not in the column list, so this still matches up to my code model-->
CreateTable(
"dbo.TableB",
c => new
{
Id = c.Int(nullable: false)
Column1 = c.Int(nullable: false)
Column2 = c.Int(nullable: false)
Column3 = c.Int(nullable: false)
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.TableA", t => t.Id)
.Index(t => t.Id);
AddColumn("dbo.TableA", "TableBId", c => c.Int());
<-- This pulls the data from tableB_Old into the newly created TableB, since TableA had a one-to-many relationship I had to get rid of duplicates this gets the first record with TableAId and discards the rest. -->
Sql("INSERT INTO [dbo].[TableB] (Id,Column1,Column2,Column3) SELECT TableAId,,Column1,Column2,Column3 FROM [dbo].[TableB_Old] where [Id] In (select min([Id]) from[dbo].[TableB_Old] as T2 where T2.TableAId = [dbo].[TableB_Old].TableAId)");
<--Now that we pulled all column data we needed from `TableB_Old` we can populate `TableA.TableBId`-->
Sql("UPDATE [TableA] SET [TableBId] = (SELECT [Id] FROM [TableB] WHERE [TableB].[Id] = [TableA].[Id])");
<-- `TableB_Old` was a good table, but it has out lived it's usefullness, it must be removed -->
DropTable("dbo.TableB_Old");
我有一个使用 EF 的代码优先 MVC 项目。
有两个表,TableA
和TableB
,它们目前是一对多的关系:
public partial class TableA
{
public TableA()
{
TableBs = new HashSet<TableB>();
}
public int Id { get; set; }
public Virtual ICollection<TableB> TableBs { get; set; }
}
public partial class TableB
{
public int Id { get; set; }
public int TableAId { get; set; }
public virtual TableA TableAs { get; set; }
}
modelBuilder.Entity<TableA>()
.HasMany(e => e.TableBs)
.WithRequired(e => e.TableA)
.HasForeignKey(e => e.TableAId);
我尝试更改 TableA
以赋予它一对零或一的关系:
public partial class TableA
{
public TableA() { }
public int Id { get; set; }
public int? TableBId { get; set; }
public virtual TableB TableB { get; set; }
}
TableB
保持不变,我像这样更改 OnModelCreating
:
modelBuilder.Entity<TableA>()
.HasOptional(e => e.TableBs);
modelBuilder.Entity<TableB>()
.HasRequired(e => e.TableAs);
问题是生成的迁移是意外的 -- 对我来说是意外的,因为我不知道我在做什么,很明显。它不是添加 FK 并添加列,而是尝试重命名列。这是我的迁移:
public override void Up()
{
DropForeignKey("dbo.TableA", "TableBId", "dbo.TableB");
DropIndex("dbo.TableA", new[] { "TableBId" });
DropColumn("dbo.TableB", "Id");
RenameColumn(table: "dbo.TableB", name: "TableBId", newName: "Id");
DropPrimaryKey("dbo.TableB");
AlterColumn("dbo.TableA", "TableBId", c => c.Int());
AlterColumn("dbo.TableB", "Id", c => c.Int(nullable: false));
AlterColumn("dbo.TableB", "TableAId", c => c.Int(nullable: false));
AddPrimaryKey("dbo.TableB", "Id");
CreateIndex("dbo.TableB", "Id");
}
我不明白为什么要重命名一个不存在的列以及我的新 FK 在哪里?
有几件事可能会导致您的问题:
流利的API通话描述关系
modelBuilder.Entity<TableA>() .HasOptional(e => e.TableBs); modelBuilder.Entity<TableB>() .HasRequired(e => e.TableAs);
因为您在这里使用了两个引用不同属性的单独调用,所以我认为 EF 有可能将其解释为两个单独的关系。另一方面,由于它们都是一对一的,所以应该没问题。无论如何,它会更有意义:
modelBuilder.Entity<TableA>() .HasOptional(e => e.TableBs) .WithRequired(t => t.TableAs);
实体之间的任何一种一对一关系都需要两种实体类型共享一个主键(其中dependent/optional方的主键也是外键),即生成的迁移一团糟的主要原因。
我认为您也有可能尝试过 运行 过去在
dbo.TableA
中创建列TableBId
的迁移。
根据jjj所说我的关系有严重的问题,我希望通过正常的迁移可以解决,但是jjj是正确的table依赖的FK和PK必须相同。我在 Azure 上使用 SQL 服务器 运行 所以我不能只删除列 TableB.Id
并将 TableB.TableAId
重命名为 TableB.Id
因为它给我一个聚集索引错误.他是对的,我的 down 语句没有下拉栏,所以我的 TableBId
仍在 dbo.TableA
。我回滚了我的数据库大约 5 次迁移。我对 TableA
的修改很好:
public partial class TableA
{
public int Id { get; set; }
public int? TableBId { get; set; }
public virtual TableB TableB { get; set; }
}
但问题出在 TableB
我不得不从模型中删除 TableAId
我在 sudo 代码中添加了列只是为了使迁移更具可读性:
public partial class TableB
{
public int Id { get; set; }
public int Column1 { get; set; }
public int Column2 { get; set; }
public int Column3 { get; set; }
public virtual TableA TableAs { get; set; }
}
现在在我的 DbContext 中,我使用了一个衬垫:
modelBuilder.Entity<TableB>()
.HasRequired(e => e.TableA).WithOptional(x => x.TableB);
当我添加迁移时,这是新创建的迁移:
public override void Up()
{
DropForeignKey("dbo.TableB", "TableAId", "dbo.TableAId");
DropIndex("dbo.TableB", new[] { "TableAId" });
DropColumn("dbo.TableB", "Id");
RenameColumn(table: "dbo.TableB", name: "TableAId", newName: "Id");
DropPrimaryKey("dbo.TableB");
AddColumn("dbo.Tenants", "TableBId", c => c.Int());
AlterColumn("dbo.TableB", "Id", c => c.Int(nullable: false));
AlterColumn("dbo.TableB", "Id", c => c.Int(nullable: false));
AddPrimaryKey("dbo.TableB", "Id");
CreateIndex("dbo.TableB", "Id");
AddForeignKey("dbo.TableB", "Id", "dbo.TableA", "Id");
}
这可能在其他版本的 SQL 中有效,但在 Azure 中无效,因为据我所知,它不允许堆 tables。所以这就是我更改迁移代码的方式。
public override void Up()
{
<-- I am renaming TableB to TableB_Old just for the migration-->
RenameTable(name: "dbo.TableB", newName: "TableB_Old");
DropForeignKey("dbo.TableB", "TableAId", "dbo.TableA");
DropIndex("dbo.TableB_Old", new[] { "TableAId" });
AlterColumn("dbo.TableB_Old", "TableAId", c => c.Int(nullable: false));
<-- Create a new TableB with the correct layout notice TableAId is not in the column list, so this still matches up to my code model-->
CreateTable(
"dbo.TableB",
c => new
{
Id = c.Int(nullable: false)
Column1 = c.Int(nullable: false)
Column2 = c.Int(nullable: false)
Column3 = c.Int(nullable: false)
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.TableA", t => t.Id)
.Index(t => t.Id);
AddColumn("dbo.TableA", "TableBId", c => c.Int());
<-- This pulls the data from tableB_Old into the newly created TableB, since TableA had a one-to-many relationship I had to get rid of duplicates this gets the first record with TableAId and discards the rest. -->
Sql("INSERT INTO [dbo].[TableB] (Id,Column1,Column2,Column3) SELECT TableAId,,Column1,Column2,Column3 FROM [dbo].[TableB_Old] where [Id] In (select min([Id]) from[dbo].[TableB_Old] as T2 where T2.TableAId = [dbo].[TableB_Old].TableAId)");
<--Now that we pulled all column data we needed from `TableB_Old` we can populate `TableA.TableBId`-->
Sql("UPDATE [TableA] SET [TableBId] = (SELECT [Id] FROM [TableB] WHERE [TableB].[Id] = [TableA].[Id])");
<-- `TableB_Old` was a good table, but it has out lived it's usefullness, it must be removed -->
DropTable("dbo.TableB_Old");