我目前正在尝试将一些本地数据带入使用EF Code-First迁移的数据库中。这些数据已经具有唯一ID,因此最初应该按原样插入第一个“数据集”。
现在我想首先设置'DatabaseGeneratedOption.None',将数据集添加到数据库,计算最后使用的ID,使用T-SQL命令'dbcc checkident重新设置(tablename,reseed,[NEW AUTO ID] )'然后在将GeneratedOption重置为'DatabaseGeneratedOption.Identity'时添加另一个迁移。
这是正确的方法和/或甚至可能,还是我走错了路?
任何线索将不胜感激 最好的祝福
编辑 - Michals回答
试图实现Michals的答案,但仍然由数据库“生成”ID,我的显式值被忽略。也许这是我插入值的方式:
MyDbContext context = // GetContext;
DbSet<SomeClass> dbSet = context.SomeClass;
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT " + someClassTableName + " ON");
foreach(SomeClass sc in toAdd)
{
// sc already contains all data including its unique ID
sbSet.Add(sc);
}
context.SaveChanges();
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT " + someClassTableName + " OFF");
解决方案/ w Michals答案
好吧,我尽力以不同的方式实现Michals的答案,最终找到了一个(非常奇怪的)解决方案。
首先,我有我的DBContext类,并从那个名为DBContext Editor的派生类。这样做只不过是重写OnModelCreating,我改变了所有'Identity'属性。
public class MyContextEditor : MyContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<SomeClass>()
.Property(e => e.ID)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
}
}
将这个类与其他帖子中的一些其他技术结合使用(下面的来源)最终给了我正在寻找的结果。 最后我有这样的事情:
MyContext context = new MyContextEditor();
DbSet<SomeClass> dataSet = context.SomeClass;
// this.Clear(dataSet); Just for testing to reset Identity Auto ID and remove all Data
// this.Reset(dataSet);
context.Database.Connection.Open();
// Add data to dataSet...
// dataSet.Add(toAdd);
// Apply Michals answer and save
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT " + tableName + " ON");
context.SaveChanges();
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT " + tableName + " OFF");
// Close Connection
context.Database.Connection.Close();
我还尝试实现了覆盖MyContext类的覆盖,该类以错误结尾“烘焙模型不同......”,这也将ID属性更改为不再是“身份”。
最后,这种方法使我能够控制添加身份数据,同时保持生成身份值的可能性。另外,任何进一步的迁移都不会改变模型,也不会删除“Identity”标志,而[DatabaseGeneratedOption]确实删除了它。也可以并建议将其存储在使用中,如下所示:
using( var transaction = context.Database.BeginTransaction'))
仅供参考伪码中的模型
class SomeClass
{
[Key]
public int ID { get; set; }
public string Title { get; set; }
// More Properties
}
相关文章和来源
我个人做的是以下内容:
SET IDENTITY_INSERT sometableWithIdentity ON
SET IDENTITY_INSERT sometableWithIdentity OFF
。播种数据时,我将所有实体附加到上下文中,添加为预先存在的Id。
唯一的问题是有时候如果有外键的循环引用。为了解决这个问题,我删除了外键的一侧,添加了所有实体,并将外键放回原处。
例如。如果我有以下内容:
public class Customer
{
public List<Address> Addresses { get; set; }
public long? DefaultAddressId { get; set; }
public Address DefaultAddress { get; set; }
}
public class Customer
{
public long Id { get; set; }
public long CustomerId { get; set; }
public Customer Customer { get; set; }
}
我会做类似以下的事情:
Customer.DefaultAddressId
+ Customer
es作为Address
EntityState.New
保存到DBContext.SaveChanges()
重新附加到跟踪客户Customer.DefaultAddressId
保存默认地址Id另一种选择是尽可能在种子期间关闭参照完整性。但是因为我们使用多个数据库(Sqlite用于本地开发,PostegreSql用于prod,有时用于MariaDb)我们无法成功将其关闭+将其重新打开+强制检查是否存在参照完整性/