使用EntityFramework 6 Code-First播种期间的IDENTITY_INSERT

Rik*_*Rak 24 c# entity-framework entity-framework-6

我有一个有Auto-identity (int)列的实体.作为数据种子的一部分,我想在我的系统中使用"标准数据"的特定标识符值,之后我想让数据库整理id值.

到目前为止,我已经能够IDENTITY_INSERT将插件批处理设置为On,但实体框架不会生成包含该插件的插入语句Id.这是有道理的,因为模型认为数据库应该提供值,但在这种情况下,我想提供值.

模型(伪代码):

public class ReferenceThing
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id{get;set;}
    public string Name{get;set;}
}

public class Seeder
{
    public void Seed (DbContext context)
    {

        var myThing = new ReferenceThing
        {
            Id = 1,
            Name = "Thing with Id 1"
        };

        context.Set<ReferenceThing>.Add(myThing);

        context.Database.Connection.Open();
        context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT ReferenceThing ON")

        context.SaveChanges();  // <-- generates SQL INSERT statement
                                //     but without Id column value

        context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT ReferenceThing OFF")
    }
}
Run Code Online (Sandbox Code Playgroud)

任何人都能提供任何见解或建议吗?

Rik*_*Rak 10

所以我可能通过生成我自己的包含Id列的SQL插入语句来解决这个问题.这感觉就像一个可怕的黑客,但它的工作原理: - /

public class Seeder
{
    public void Seed (DbContext context)
    {

        var myThing = new ReferenceThing
        {
            Id = 1,
            Name = "Thing with Id 1"
        };

        context.Set<ReferenceThing>.Add(myThing);

        context.Database.Connection.Open();
        context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT ReferenceThing ON")

        // manually generate SQL & execute
        context.Database.ExecuteSqlCommand("INSERT ReferenceThing (Id, Name) " +
                                           "VALUES (@0, @1)", 
                                           myThing.Id, myThing.Name);

        context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT ReferenceThing OFF")
    }
}
Run Code Online (Sandbox Code Playgroud)


Chr*_*ris 7

我为我创建了一个替代构造函数,DbContext它需要一个bool allowIdentityInserts.我把那个bool设置为一个同名的私有字段DbContext.

OnModelCreating再"unspecifies"身份,如果我创建的"模式"上下文规范

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

        if(allowIdentityInsert)
        {
            modelBuilder.Entity<ChargeType>()
                .Property(x => x.Id)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
        }
    }
Run Code Online (Sandbox Code Playgroud)

这允许我插入Ids而不更改我的实际数据库标识规范.我仍然需要使用你所做的身份插入开/关技巧,但至少EF会发送Id值.

  • 我认为使用 HasDatabaseGenerateOption(DatabaseGenerateOption.None) 的问题是,当您将应用程序与实体框架一起使用时,插入将失败,因为 EF 现在期望为任何插入提供 ID。 (2认同)

小智 2

如果没有第二个 EF 级别模型就无法完成 - 复制用于播种的类。

正如您所说 - 您的元数据表明数据库提供了该值,但在播种期间却没有提供该值。