我目前正在尝试将一些本地数据带入使用EF Code-First镜像的数据库中。这些数据已经具有唯一的ID,因此最初应按原样插入数据的第一个“集合”。
现在我正在考虑首先设置'DatabaseGeneratedOption.None', 将数据集添加到数据库,计算最后使用的ID,然后使用T-SQL命令“ dbcc checkident(表名,种子,[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答案
好吧, 我尽了最大的努力以不同的方式实现米歇尔人的答案,最后得出了(真的很奇怪)的解决方案。
首先,我有我的DBContext类,然后是一个名为DBContextEditor的派生类。要做的就是覆盖我更改所有“身份”属性的OnModelCreating。
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
}
相关文章和来源
答案 0 :(得分:0)
我个人要做的事情如下:
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
+ Address
附加为EntityState.New
Context.SaveChanges()
保存到数据库Customer.DefaultAddressId
到被跟踪的客户Context.SaveChanges()
保存默认的地址ID 另一个选择是,如果可能的话,关闭种子期间的参照完整性。但是,由于我们使用多个数据库(Sqlite用于本地开发,PostegreSql用于产品,有时甚至是MariaDb),我们无法成功将其关闭+重新打开+强制检查是否存在参照完整性/