使用实体框架手动输入密钥

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 =&gt; 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,但该列仍然是自动生成的。 以后有没有其他方法可以应用更改。因为在我的情况下,我不能删除数据库。有一些数据存在。我只是希望它在迁移运行时重新应用这些更改。所以我把所有需要的东西都放在了模型创建中。但即使在运行迁移之后它也无法正常工作。

以上是关于使用实体框架手动输入密钥的主要内容,如果未能解决你的问题,请参考以下文章

使用机器人框架手动输入(验证码)?

实体框架“指定的密钥太长;最大密钥长度为 1000 字节”

实体框架:在关联中使用非主要唯一键的替代解决方案

如何在 Linux Mint 中以编程方式发送密钥(模拟密钥输入)?

指定的密钥太长;实体框架 6 中的最大密钥长度为 767 字节 Mysql 错误

在编辑视图中保留实体密钥的更安全方法?