Kgn*_*web 11 c# asp.net entity-framework entity-framework-core ef-core-2.1
我正在使用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; }
}
Run Code Online (Sandbox Code Playgroud)
但是我意识到同时拥有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; }
}
Run Code Online (Sandbox Code Playgroud)
而在DbContext类中,定义主体实体如下。
HasOne(b => b.Customer).WithOne(c => c.BankAccount).HasForeignKey<BankAccount>(f => f.Id);
Run Code Online (Sandbox Code Playgroud)
运行时,update-database
我得到以下错误。
System.InvalidOperationException:要更改列的IDENTITY属性,需要删除并重新创建该列。
但是,理想情况下,我不应该只是摆脱这个错误,而是删除列,约束以及表,然后删除完整的数据库。但是还是一样的错误。
我有这个问题时,我试图从改变一个模型public byte Id {get; set;}
来public int Id {get; set;}
。为了解决这个问题,我做了以下几件事:
Remove-Migration -Project <target_project>
在包管理器控制台中创建目标模型ModelSnapshot
文件并将它们粘贴到您的分支中(小心覆盖它们!)。add-migration <migration_name>
在包管理器控制台中创建一个新的迁移update-database
在包管理器控制台中更新数据库我可以这样解决,因为我的代码不在生产环境中。如果模型已经在那里,也许你不得不面对另一个复杂的问题。
小智 7
我遇到了相同的问题,并通过两个步骤和两次迁移解决了这个问题:
步骤1
第2步
小智 7
我不得不:
完毕
TL;DR.:让 EF 为您做这件事。
简而言之,identity属性是数据库用来管理专用ID列的,因此它不依赖于自身之外的任何东西来识别每一行,因此bankAccount类需要它自己的Id字段来具有identity属性;现在,如果您尝试手动告诉 EF 如何处理关系,就像处理该行一样
HasOne(b => b.Customer).WithOne(c => c.BankAccount).HasForeignKey<BankAccount>(f => f.Id);
Run Code Online (Sandbox Code Playgroud)
您要做的就是覆盖 EF 本身的内部逻辑,在这种情况下,您告诉 EF 银行帐户 ID 是引用客户的字段,但事实并非如此,因此 EF 尝试从其中删除 IDENTITY银行帐户模型中的 id 字段,但这只是因为您告诉它银行帐户 Id 应与 Customer ID 相同。我想我明白您在一对一关系中想要表达的意思,但是当客户尝试开设另一个银行账户时会发生什么?D:相反,你应该保留该int CustomerId
字段并删除该Customer Customer
字段,不仅因为它更干净,而且因为只要有一个带有字段调用的类,EF 就会识别出两者之间的Customer
关系Id
。
public int CustomerId { get; set; } //keep
public Customer Customer { get; set; } //delete
Run Code Online (Sandbox Code Playgroud)
这样,客户就可以在银行开设任意数量的账户,桌子不会受到影响,并且 EF 知道该怎么做。
它将自动生成适当的外键并将其添加到迁移文件中,如下所示:
migrationBuilder.AddForeignKey(
name: "FK_BankAccount_Customer_CustomerId",
table: "BankAccount",
column: "CustomerId",
principalTable: "Customer",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
Run Code Online (Sandbox Code Playgroud)
这将反映一对多的关系,这是很好的而且花哨的。
现在,回答这个问题,如果您仍然想删除该属性:
(但它不会解决原问题的外键问题)。
首先,回顾一下:要更改标识属性,数据库管理器(mysql、sqlserver 等)将始终要求您删除并重新创建表,因为该字段是表的核心。所以你需要欺骗 EF 来为你做一个解决方法。
将第二个 Id 元素添加到模型类,其名称很明显,例如duplicateId
。
public class BankAccount
{
public int Id { get; set; }
public int duplicateId { get; set; }
...
}
Run Code Online (Sandbox Code Playgroud)
这就是窍门;)
在您实现接口的类中DbContext
,添加以下方法,告诉 ef 您希望主键是哪个字段:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BankAccount>().HasKey(x => new { x.duplicateId });
}
Run Code Online (Sandbox Code Playgroud)
添加一个新的迁移$ 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");
...
}
Run Code Online (Sandbox Code Playgroud)
然后执行数据库更新$ dotnet ef database update
(这些命令可能会有所不同,使用您之前使用过的任何语法)。
(可选)如果您需要保留原始 ID,请检查它们是否已保留,或者只是对表进行脏更新以将数据从字段复制Id
到duplicateId
.
现在原始Id
字段可以自由删除或更新,因此只需从模型中删除原始字段即可:
public class BankAccount
{
public int duplicateId { get; set; }
...
}
Run Code Online (Sandbox Code Playgroud)
如果您仍在尝试强制使用将 BankAccount Id 与客户 ID 链接的原始命令,则在此步骤运行该命令应该会起作用,但请不要这样做。
添加新的迁移$ dotnet ef migrations add ModelIdChange2
,然后使用 进行数据库更新$ dotnet ef database update
,这将删除原始Id
列并保留duplicateId
为主键。
现在,该模型看起来几乎是原始模型,但有了一个新的标识列,您可以保留它,或者只是在 BankAccount 类中将该字段重命名为duplicateId
to Id
,如下所示:
public class BankAccount
{
public int Id { get; set; }
...
}
Run Code Online (Sandbox Code Playgroud)
并执行$ dotnet ef migrations add ModelIdChange3
,然后使用 进行数据库更新$ dotnet ef database update
。
当您想要更改架构或已存在的表时尝试更改或修改已存在的表时,会发生此错误,EF 核心不支持它但需要手动操作。您可以采取以下措施:
归档时间: |
|
查看次数: |
9437 次 |
最近记录: |