我正在尝试为某些条目手动设置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", … }}
我如何使其工作?
答案 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语句。