使用实体框架手动输入键
本文关键字:手动输入键 框架 实体 | 更新日期: 2023-09-27 18:32:00
我正在尝试首先将实体框架代码用于一个简单的数据库项目,但我遇到了一个我根本无法弄清楚的问题。
我注意到 EF 每次将表的 ID 设置为自动增加 1,完全忽略我为该字段手动输入的值。经过一些搜索,我的理解是禁用此行为的正确方法是:
modelBuilder.Entity<Event>().Property(e => e.EventID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
但是现在我只是收到此错误,我不知道为什么:
未处理的异常: System.Data.Entity.Infrastructure.DbUpdateException: 一个错误 在更新条目时发生。请参阅的内部异常 详。---
System.Data.UpdateException: 更新条目时出错。有关详细信息,请参阅内部异常。---> System.Data.SqlClient.SqlException:无法插入显式值 表"事件"中的标识列(当IDENTITY_INSERT设置为 OFF 时。
如果有帮助,这里是有问题的 POCO 类:
public class Event
{
[Key, Required]
public int EventID { get; set; }
public string EventType { get; set; } //TODO: Event Type Table later on
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public virtual ICollection<Match> Matches { get; set; }
public virtual ICollection<EventParticipation> EventParticipation { get; set; }
}
提前谢谢。
由于我尽可能喜欢属性,为了完整起见,这里是另一种选择:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
注意:这也适用于 EF 核心。
默认情况下,实体框架假定整数主键是数据库生成的(相当于在 Fluent API 中添加属性HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
或调用Property(e => e.EventID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
。
如果您查看创建表的迁移,您应该看到以下内容:
CreateTable(
"dbo.Events",
c => new
{
EventID = c.Int(nullable: false, identity: true),
//etc
})
.PrimaryKey(t => t.EventID );
然后,您使用 Fluent API 将模型更改为 DatabaseGenerated.None
。EF 将其放入迁移中:
AlterColumn("dbo.Events", "EventID", c => c.Int(nullable: false, identity: false))
生成的 sql 是这样的:
ALTER TABLE [dbo].[Events] ALTER COLUMN [EventID] [int] NOT NULL
这居然是蹲着的。从列中删除 IDENTITY 并非易事。您需要删除并重新创建表或创建新列,然后必须复制数据并修复外键。因此,EF 没有为你这样做也就不足为奇了。
你需要弄清楚如何最好地为自己做这件事。现在,您可以回滚迁移到 0 并从头开始重新搭建基架,因为您已经指定了 DatabaseGeneratedOption.None
,或者您可以手动更改迁移以删除并重新创建表。
或者,您可以删除并重新创建列:
DropColumn("Customer", "CustomerId");
AddColumn("Customer", "CustomerId", c => c.Long(nullable: false, identity: false));
编辑或者,您可以使用自定义迁移操作打开/关闭标识