IDENTITY_INSERT ON错误与外键

时间:2018-09-26 10:34:25

标签: entity-framework entity-framework-6

我正在尝试为某些条目手动设置ID。

我有一个带“标识”字段的Customer类

  modelBuilder.Entity<Customer>().Property(f => f.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);

在插入部分中有

    using (var transaction = ctx.Database.BeginTransaction())
    {
      ctx.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [dbo].[Customers] ON");
      ctx.Customers.AddRange(customersList);
      ctx.SaveChanges();
      ctx.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [dbo].[Customers] OFF");
      transaction.Commit();
    }

但我仍然遇到异常

  

必须为表中的标识列指定显式值   当IDENTITY_INSERT设置为ON或当   复制用户正在插入NOT FOR REPLICATION身份   列。

在我的异常的StateEntries中,我可以看到存储在另一个表(例如“ Contacts”)中的所有字段似乎是原因 customer.Contacts = new List<Contact> {new Contact {Name = "Test", … }}

我如何使其工作?

1 个答案:

答案 0 :(得分:1)

该错误消息具有误导性。您已成功打开IDENTITY_INSERT,但是在假定键值将由IDENTITY列生成的前提下,EF仍在生成INSERT语句。

因此,您另外必须生成一个包含键值的INSERT语句。当然,您也可以使用.ExecuteSqlCommand()来执行INSERT。或者,您可以使用EF来执行此操作,但是必须使用该实体没有数据库生成键的模型。 OnModelCreating每个ModelType仅配置一次模型,因此您不能只在其中放置一个开关。

相反,您可以创建DbContext的子类型进行播种,从而覆盖基础DbContext的实体配置。像这样:

class Db_Seed: Db
{
    public Db_Seed(string constr) : base(constr)
    {
        Database.SetInitializer<Db_Seed>(null);  //no initializer
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<Customer>().Property(c => c.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
    }
}

still 必须将IDENTITY_INSERT设置为on(因为该表确实具有IDENTITY),但是在这种情况下,EF不会生成假定服务器将生成密钥的INSERT语句。