实体框架代码第一次迁移:设置主键值

时间:2013-03-19 20:17:34

标签: ef-code-first primary-key entity-framework-5 ef-migrations

我有一个表,可以为表的某些行存储一些额外的数据,如:

public class QuoteExtra
{
    [Key]
    public int QuoteId { get; set; }
    // More fields here
}

我希望能够在此表中添加明确设置PK的行。

如果我只是如上所述,设置一个值并提交该行会导致该值被丢弃并替换为数据库中自动生成的值(并且该列被定义为实际模式中的Identity列)

这似乎是正确的解决方案:

public class QuoteExtra
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int QuoteId { get; set; }
    // More fields here
}

然而,这反而让我成为例外:

  

当IDENTITY_INSERT设置为OFF时,无法在表'EnumTest'中为identity列插入显式值。

那么,我如何编写课程以便能够在EF中设置主键的值?

编辑:

我尝试添加以下基于代码的迁移,将IDENTITY_INSERT设置为ON:

public override void Up()
{
    Sql("SET IDENTITY_INSERT QuoteExtra ON");
}

我跑了又试了一次,但得到了与上面相同的例外。奇怪的是,数据库确实反映了这个设置,并且直接运行SQL确实允许我为主键插入任意值 - 因此看起来实体框架本身正在执行此规则,而忽略了识别IDENTITY_INSERT不在事实定下来了。我是否需要在EF本身设置它?

编辑2:

我误解了IDENTITY_INSERT;我假设将它设置为无限期地保留在该表中。实际上它只要“会话”就可以存在,这意味着例如在迁移中设置它意味着它只存在......只要迁移运行,并且与我以后的.Add()之后的未来连接没有关系。 ,这解释了为什么我仍然有这个例外 - 数据库确实是异常的来源,而不是EF。由于IDENTITY_INSERT每个会话最多限制一个表,因此这是一种相当低效的方法 - 首先不创建Identity PK列似乎是更好的路径。

3 个答案:

答案 0 :(得分:34)

这是在没有启用Identity Autoincrement的情况下创建PK的正确方法:

public class QuoteExtra
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int QuoteId { get; set; }
    // More fields here
}

但是,如果在EF迁移已经创建表之后添加DatabaseGenerated(DatabaseGeneratedOption.None)],则它会对表静默地执行任何操作。如果这是您的方案,则需要添加手动迁移以删除表:

add-migration RecreateQuoteExtra

在迁移中:

public override void Up()
{
    DropTable("QuoteExtra");
}

EF自动迁移将自动重新创建没有Identity约束的表,这将允许您随时设置PK值,而无需运行任何特殊命令,如IDENTITY_INSERT ON。

这听起来像是一种破坏性较小的方式来自EF7(“数据运动”),或者您可以在迁移中自己编写大量手动sql来创建临时表并在需要避免时移动数据丢失表中的现有数据。

编辑:根据您的情况,EF迁移可能无法重新创建表 - 如果该类已经存在并且已经添加到您的DbContext中,它将丢弃它并将其保留在该表上,这意味着您的手动迁移不仅要删除,而且还创建表。由于EF Migrations为添加迁移为您生成的脚手架代码将为您创建这些语句,但这不是什么大问题,但是需要更多代码来检查问题。

答案 1 :(得分:4)

这是正确的解决方案,但仅适用于新表。如果更改现有表的数据库生成选项,则EF迁移无法执行此更改,并且QuoteId列仍在数据库中标记为Identity

答案 2 :(得分:1)

我可以用你的提示解决这个问题,然后我试图重新创建整个数据库,但它也没有用。

要解决此问题,您必须在第一个(!)创建列时删除 identity:true 属性(例如初始迁移)。

也许它会帮助别人..

相关问题