使用 EF Code-First 迁移仅为初始数据插入身份
Identity Insert just for initial Data with EF Code-First Migrations
我目前正在尝试将一些本地数据导入使用 EF Code-First 迁移的数据库中。这些数据已经具有唯一 ID,因此最初应按原样插入第一个 'set' 数据。
现在我想先设置'DatabaseGeneratedOption.None',
将数据集添加到数据库,计算最后使用的 ID,使用 T-SQL 命令重新播种 'dbcc checkident (tablename, reseed, [NEW AUTO ID])'
然后在将 GeneratedOption 重置为 'DatabaseGeneratedOption.Identity'.
的同时添加另一个迁移
这是正确的方法吗and/or甚至可能还是我走错了路?
如有任何线索,我们将不胜感激
最好的问候
编辑 - 迈克尔斯回答
已尝试执行 Michals 的回答,但 ID 仍然是数据库 'generated',我的显式值被忽略了。也许这是我插入值的方式:
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 answers
嗯,
我尽我最大的努力以不同的方式实现迈克尔斯的答案,最终得出了一个(非常奇怪的)解决方案。
首先,我有我的 DBContext class 并且从中派生了一个名为 DBContextEditor 的 class。所做的就是覆盖 OnModelCreating,我更改了所有 'Identity' 属性。
public class MyContextEditor : MyContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<SomeClass>()
.Property(e => e.ID)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
}
}
将此 class 与其他帖子(参见下面的资源)中的其他一些技术结合使用,最终得到了我想要的结果。
最后我得到了这样的东西:
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 class 中实现覆盖,结果出现错误 'the baking model is different...',这也将 ID 属性 更改为不再是 'identity'.
最后,这种方法使我能够对添加身份数据进行所需的控制,同时保持生成身份值的可能性。此外,任何进一步的迁移都不会更改模型,也不会删除 'Identity' 标志,而 [DatabaseGeneratedOption] 确实删除了它。
也可以并建议将其存储在 using 中,如下所示:
using( var transaction = context.Database.BeginTransaction'))
伪代码模型仅供参考
class SomeClass
{
[Key]
public int ID { get; set; }
public string Title { get; set; }
// More Properties
}
相关帖子和来源
- Answer from this Post (Identity Insert)
- Another Question related to Identity Inserts
我个人的做法是:
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
到第 2 步中跟踪的客户
Context.SaveChanges()
保存默认地址Id的
另一种选择是尽可能在种子期间关闭参照完整性。但是当我们使用多个数据库时(Sqlite 用于本地开发,PostegreSql 用于生产,有时还有 MariaDb)我们无法成功关闭它 + 重新打开它 + 强制检查是否存在参照完整性/
我目前正在尝试将一些本地数据导入使用 EF Code-First 迁移的数据库中。这些数据已经具有唯一 ID,因此最初应按原样插入第一个 'set' 数据。
现在我想先设置'DatabaseGeneratedOption.None', 将数据集添加到数据库,计算最后使用的 ID,使用 T-SQL 命令重新播种 'dbcc checkident (tablename, reseed, [NEW AUTO ID])' 然后在将 GeneratedOption 重置为 'DatabaseGeneratedOption.Identity'.
的同时添加另一个迁移这是正确的方法吗and/or甚至可能还是我走错了路?
如有任何线索,我们将不胜感激
最好的问候
编辑 - 迈克尔斯回答
已尝试执行 Michals 的回答,但 ID 仍然是数据库 'generated',我的显式值被忽略了。也许这是我插入值的方式:
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 answers
嗯, 我尽我最大的努力以不同的方式实现迈克尔斯的答案,最终得出了一个(非常奇怪的)解决方案。
首先,我有我的 DBContext class 并且从中派生了一个名为 DBContextEditor 的 class。所做的就是覆盖 OnModelCreating,我更改了所有 'Identity' 属性。
public class MyContextEditor : MyContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<SomeClass>()
.Property(e => e.ID)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
}
}
将此 class 与其他帖子(参见下面的资源)中的其他一些技术结合使用,最终得到了我想要的结果。
最后我得到了这样的东西:
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 class 中实现覆盖,结果出现错误 'the baking model is different...',这也将 ID 属性 更改为不再是 'identity'.
最后,这种方法使我能够对添加身份数据进行所需的控制,同时保持生成身份值的可能性。此外,任何进一步的迁移都不会更改模型,也不会删除 'Identity' 标志,而 [DatabaseGeneratedOption] 确实删除了它。 也可以并建议将其存储在 using 中,如下所示:
using( var transaction = context.Database.BeginTransaction'))
伪代码模型仅供参考
class SomeClass
{
[Key]
public int ID { get; set; }
public string Title { get; set; }
// More Properties
}
相关帖子和来源
- Answer from this Post (Identity Insert)
- Another Question related to Identity Inserts
我个人的做法是:
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
到第 2 步中跟踪的客户 Context.SaveChanges()
保存默认地址Id的
另一种选择是尽可能在种子期间关闭参照完整性。但是当我们使用多个数据库时(Sqlite 用于本地开发,PostegreSql 用于生产,有时还有 MariaDb)我们无法成功关闭它 + 重新打开它 + 强制检查是否存在参照完整性/