我正在使用 EF Core 2.1
这是我最初的模型定义。
public class Customer //Parent
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public BankAccount BankAccount { get; set; }
}
public class BankAccount
{
public int Id { get; set; }
public string Branch { get; set; }
public string AcntNumber { get; set; }
public DateTime CreatedDate { get; set; }
public int CustomerId { get; set; }
public Customer Customer { get; set; }
}
但是我意识到同时拥有Id
和CustomerId
是一对一的关系,因此我可以如下更新我的BankAccount模型定义。
public class BankAccount
{
public int Id { get; set; }
public string Branch { get; set; }
public string AcntNumber { get; set; }
public DateTime CreatedDate { get; set; }
public Customer Customer { get; set; }
}
虽然在DbContext类中定义了以下主体实体。
HasOne(b => b.Customer).WithOne(c => c.BankAccount).HasForeignKey<BankAccount>(f => f.Id);
运行update-database
时,出现以下错误。
System.InvalidOperationException:要更改列的IDENTITY属性,需要删除并重新创建该列。
但是,理想情况下,我不应该只是摆脱这个错误,而是删除列,约束以及表,然后删除完整的数据库。但是仍然是相同的错误。
答案 0 :(得分:2)
我想比建议的“解决方案”要删除所有迁移,然后重新创建它,这意味着人们从来没有进入过生产环境,那么,我希望您已经解决了这个问题,但是,出于文档目的,我分享该链接说明了您所需要了解的所有有关密钥及其更改方法(无需删除迁移即可解决此问题)
https://thisworksonmymachine.com/2017/02/13/ef-core-the-setup-part-4/
另一个选项(不是我所做的)是从上一次迁移中删除主数据库的更改,然后从SQL手动删除它,在sql上手动添加新的主数据库,并且模型如何与您匹配不会出现问题。 / p>
答案 1 :(得分:1)
当您想要更改架构或已经存在的表(当EF核心不支持它但它需要手动操作)时,当您尝试更改或修改已经存在的表时,会发生此错误。这是您可以采取的措施:
答案 2 :(得分:1)
当我尝试将模型从public byte Id {get; set;}
更改为public int Id {get; set;}
时遇到了这个问题。
面对这个问题,我做了以下事情:
Remove-Migration -Project <target_project>
创建目标模型为止ModelSnapshot
文件并将其粘贴到分支中(仔细覆盖它们) !)。add-migration <migration_name>
创建新迁移update-database
更新数据库我可以用这种方式解决它,因为我的代码不在生产环境中。如果模型已经存在,也许您就不得不面对另一个复杂的问题。
答案 3 :(得分:1)
在我的例子中,表 SharedBalances 被重命名为 Balances,它的标识列 SharedBalancesId 被重命名为 BalanceId。 SQL 命令在 SQL Server 上执行。你也可以试试migrationBuilder.Sql(my_sql_command_here)
我创建了迁移并遇到了同样的错误。
使用TSQL命令重命名列和表:
/*
migrationBuilder.RenameTable(
name: "SharedBalances",
newName: "Balances");
*/
在迁移中注释 RenameTable 命令:
/*
migrationBuilder.DropPrimaryKey(
name: "PK_SharedBalances",
table: "Balances");
migrationBuilder.AddPrimaryKey(
name: "PK_Balances",
table: "Balances",
column: "BalanceId");
*/
注释迁移中的 AddPrimaryKey 命令:
migrationBuilder.DropForeignKey(
name: "FK_SharedBalances_Users_OwnerUserId",
table: "SharedBalances");
migrationBuilder.DropPrimaryKey(
name: "PK_SharedBalances",
table: "SharedBalances");
在迁移中更新出现的表名 DropForeignKey 命令:
从此....
migrationBuilder.DropForeignKey(
name: "FK_SharedBalances_Users_OwnerUserId",
table: "Balances");
migrationBuilder.DropPrimaryKey(
name: "PK_SharedBalances",
table: "Balances");
为此:
TopologyTestDriver
现在您的迁移将起作用。事情是这样发生的:
答案 4 :(得分:1)
TL;DR.:让 EF 为您做。
简而言之,identity 属性是 DB 用来管理一个专用 ID 列的东西,所以它不依赖于任何外部的东西来识别每一行,因此 bankAccount 类需要它自己的 Id 字段来拥有 identity 属性;现在,如果您尝试手动告诉 EF 如何处理关系,就像您对线所做的那样
HasOne(b => b.Customer).WithOne(c => c.BankAccount).HasForeignKey<BankAccount>(f => f.Id);
您所做的是覆盖 EF 本身的内部逻辑,在这种情况下,您告诉 EF 银行帐户 ID 是引用客户的字段,事实并非如此,因此 EF 尝试删除来自银行帐户模型中 id 字段的 IDENTITY,但这只是因为您告诉它银行帐户 ID 应该与客户 ID 相同。
我想我理解您想通过一对一关系表达的意思,但是当客户尝试开设另一个银行账户时会发生什么?乙:
相反,您应该保留 int CustomerId
字段并删除 Customer Customer
字段,不仅因为它更干净,而且因为只要有一个名为 {{1} 的类,EF 就会识别两者之间的关系}} 带有字段 Customer
。
Id
因此,客户可以根据需要在银行开设任意数量的账户,桌子不会受到影响,EF 知道该怎么做。
它会自动生成适当的外键并将其添加到迁移文件中,如下所示:
public int CustomerId { get; set; } //keep
public Customer Customer { get; set; } //delete
这将反映一对多的关系,这很好很花哨。
现在回答这个问题,如果你仍然想放弃这个属性:
(但它不会解决原始问题的外键问题)。
首先,回顾一下:要更改身份属性,数据库管理器(mysql、sqlserver 等)将始终要求您删除并重新创建表,因为该字段是表的核心。所以你需要欺骗 EF 为你做一个解决方法。
将第二个 Id 元素添加到模型类,并使用类似 migrationBuilder.AddForeignKey(
name: "FK_BankAccount_Customer_CustomerId",
table: "BankAccount",
column: "CustomerId",
principalTable: "Customer",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
的明显名称。
duplicateId
这就是诀窍 ;)
在实现 public class BankAccount
{
public int Id { get; set; }
public int duplicateId { get; set; }
...
}
接口的类中,添加以下方法,告诉 ef 您想要哪个字段主键是:
DbContext
使用 protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BankAccount>().HasKey(x => new { x.duplicateId });
}
添加一个新的迁移,因为这会更改表的主键并且迁移 $ dotnet ef migrations add ModelIdChange1
方法应该看起来像这样:
Up
然后使用 protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropPrimaryKey(
name: "PK_BankAccount",
table: "BankAccountTableName");
migrationBuilder.AddColumn<int>(
name: "duplicateId",
table: "BankAccountTableName",
type: "int",
nullable: false,
defaultValue: 0)
.Annotation("SqlServer:Identity", "1, 1");
migrationBuilder.AddPrimaryKey(
name: "PK_BankAccount",
table: "BankAccountTableName",
column: "duplicateId");
...
}
进行数据库更新(这些命令可能会有所不同,请使用您之前使用过的任何语法)。
(可选)如果您需要保留原始 ID,请检查它们是否已保留,或者只是对表进行脏更新以将数据从 $ dotnet ef database update
字段复制到 {{1 }}。
现在原始的 Id
字段可以自由删除或更新,所以继续从模型中删除原始字段:
duplicateId
如果您仍在尝试强制使用将 BankAccount Id 与客户的 Id 关联的原始命令,则在此步骤运行该命令应该可以正常工作,但请不要这样做。
并用Id
添加一个新的Migration,然后用public class BankAccount
{
public int duplicateId { get; set; }
...
}
做数据库更新,删除原来的$ dotnet ef migrations add ModelIdChange2
列,留下$ dotnet ef database update
作为主键。
现在,模型看起来几乎是原始模型,但是有了一个新的标识列,您可以保持原样,或者只是将 BankAccount 类中的字段从 Id
重命名为 duplicateId
像这样:
duplicateId
并执行 Id
,然后使用 public class BankAccount
{
public int Id { get; set; }
...
}
执行数据库更新。
答案 5 :(得分:1)
entity.ToTable("BankAccount2")
Add-Migration BankAccountTempChanges
Update-Database
entity.ToTable("BankAccount")
Add-Migration BankAccountOk
Update-Database
答案 6 :(得分:0)
我删除了Migrations文件夹和自动生成的_EFMigrationHistory
保险箱。再次在软件包管理器控制台和Add-Migration
命令上运行Update-Database
MigrationName,问题已解决。
答案 7 :(得分:0)
我遇到了同样的问题,我通过两个步骤和两次迁移解决了这个问题:
答案 8 :(得分:0)
在我看来,对除开发数据库以外的任何文件运行EF迁移会带来麻烦,因为您自然会受到以下事实的束缚:EF迁移有时会在更改对象的结构(更改主键和更改)时断然拒绝工作外键是最常遇到的问题。
多年来,我一直使用工具来确保数据库模式包含在版本控制中(与EF迁移互补)。做您的开发来更改您的dev数据库(数据并不重要),创建多个迁移,然后使用这些工具将它们汇总到数据库部署脚本中。
以下是我在这种情况下的操作摘要:-
BankAccount
的所有引用BankAccount
类现实情况是,如果您要使用代码优先方法从根本上改变生产结构的生产数据,那么除非您了解并解决了从一种结构到另一种结构的数据迁移问题,否则对您来说可能会很糟糕。
答案 9 :(得分:0)
我必须:
完成
答案 10 :(得分:0)
请按照以下步骤操作:
1-请在 sql server 中更改所有标识列(不在您的代码优先实体框架中)
迁移中的 2 条注释标识列更改(.cs 文件)
3-更新数据库
享受吧
答案 11 :(得分:0)
我遇到了同样的问题(就我而言,表中没有任何数据),我以这种方式解决了它(这不是正确的方法,但对我有用):
答案 12 :(得分:0)
对于像我这样懒惰的人:您想将主键列 "Id" 的数据类型从 int 更改为 Guid在一个名为“翻译”的表格中,就像我的情况一样。
migrationBuilder.AlterColumn<Guid>(
name: "Id",
table: "Translations",
type: "uniqueidentifier",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
OldAnnotation("SqlServer:Identity", "1, 1");
您可以删除或评论该内容
migrationBuilder.DropPrimaryKey(
name: "PK_Translations",
table: "Translations");
<块引用>
migrationBuilder.DropColumn(
name: "Id",
table: "Translations");
<块引用>
migrationBuilder.AddColumn<Guid>(
name: "Id",
table: "Translations",
type: "uniqueidentifier",
nullable: false);
记得在 Down override 方法中做相反的事情,以防你可能想要反向迁移
答案 13 :(得分:0)
我遇到了类似的问题,我将表配置的关系导航组件从 WithMany
更改为 WithRequiredDependent
。实体框架想要删除索引并重新创建列,即使数据库中的任何内容都不应该改变。
为了解决这个问题,我重新搭建了最新的迁移,它允许实体在不创建任何新迁移的情况下吸收更改。您可以通过从目标数据库恢复迁移并使用完全相同的迁移名称为最新迁移重新运行 Add-Migration
脚本来重新构建最新迁移。