使用实体框架手动输入密钥
Posted
技术标签:
【中文标题】使用实体框架手动输入密钥【英文标题】:Entering keys manually with Entity Framework 【发布时间】:2013-09-25 06:56:44 【问题描述】:我正在尝试首先将实体框架代码用于一个简单的数据库项目,但遇到了一个我根本无法弄清楚的问题。
我注意到 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;
提前致谢。
【问题讨论】:
注意:您也可以直接在属性本身上使用属性,如果您发现它可以更轻松地维护您的模型。[DatabaseGeneratedAttribute(DatabaseGeneratedOption.None)]
【参考方案1】:
由于我更喜欢属性,为了完整起见,这里是替代方案:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id get; set;
注意:这也适用于 EF Core。
【讨论】:
【参考方案2】:默认情况下,Entity Framework 假定整数主键是数据库生成的(相当于在 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
实际上确实是蹲着。来自列的Dropping the IDENTITY 并非微不足道。您需要删除并重新创建表或创建一个新列,然后您必须复制数据并修复外键。因此,EF 不为您这样做也就不足为奇了。
您需要弄清楚如何最好地为自己做这件事。既然您已经指定了 DatabaseGeneratedOption.None
,您可以将迁移回滚到 0 并从头开始重新构建脚手架,或者您可以手动更改迁移以删除并重新创建表。
或者您可以删除并重新创建该列:
DropColumn("Customer", "CustomerId");
AddColumn("Customer", "CustomerId", c => c.Long(nullable: false, identity: false));
编辑 或者你可以Switch Identity On/Off With A Custom Migration Operation
【讨论】:
谢谢。我最终设法通过删除整个数据库并让 EF 从头开始创建它来修复它。现在我知道为什么会这样了,以后我只需要放下桌子。 我从一开始就使用 Fluent API 设置了 DatabaseGenerated.None,但该列仍然是自动生成的。 以后有没有其他方法可以应用更改。因为在我的情况下,我不能删除数据库。有一些数据存在。我只是希望它在迁移运行时重新应用这些更改。所以我把所有需要的东西都放在了模型创建中。但即使在运行迁移之后它也无法正常工作。以上是关于使用实体框架手动输入密钥的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Linux Mint 中以编程方式发送密钥(模拟密钥输入)?