如何强制实体框架插入标识列?
如何强制实体框架插入标识列?
我想用一些C#代码来初始化我的数据库,并插入一些种子数据。显然,这将需要能够在插入时设置各种标识列的值。我采用了代码优先的方法。默认情况下,DbContext
处理数据库连接,所以无法使用SET IDENTITY_INSERT [dbo].[MyTable] ON
。因此,我目前所做的是使用允许我指定要使用的数据库连接的DbContext
构造函数。然后,在该数据库连接中设置IDENTITY_INSERT
为ON
,然后尝试使用Entity Framework插入我的记录。下面是我目前的示例:
public class MyUserSeeder : IEntitySeeder { public void InitializeEntities(AssessmentSystemContext context, SqlConnection connection) { context.MyUsers.Add(new MyUser { MyUserId = 106, ConceptPersonId = 520476, Salutation = "Mrs", Firstname = "Novelette", Surname = "Aldred", Email = null, LoginId = "520476", Password="28c923d21b68fdf129b46de949b9f7e0d03f6ced8e9404066f4f3a75e115147489c9f68195c2128e320ca9018cd711df", IsEnabled = true, SpecialRequirements = null }); try { connection.Open(); SqlCommand cmd = new SqlCommand("SET IDENTITY_INSERT [dbo].[MyUser] ON", connection); int retVal = cmd.ExecuteNonQuery(); context.SaveChanges(); } finally { connection.Close(); } } }
如此接近,却又如此遥远 - 因为,虽然cmd.ExecuteNonQuery()
工作正常,但当我运行context.SaveChanges()
时,我收到了一个通知:“在将IDENTITY_INSERT设置为ON时,或者在复制用户插入到一个NOT FOR REPLICATION标识列时,必须为'MyUser'表中的标识列指定显式值。”
也许是因为MyUserId(即MyUser表中的标识列)是主键,所以当我调用context.SaveChanges()
时,Entity Framework不会尝试设置它,即使我为MyUser
实体的MyUserId
属性提供了一个值。
有没有办法强制Entity Framework尝试插入实体的主键值?或者有没有办法暂时将MyUserId
标记为不是主键值,这样EF就会尝试插入它?
如何强制实体框架插入自增列?
有人在EF5与DB first中遇到了这个问题:我无法让任何解决方案起作用,但我找到了另一个解决办法:
在运行.SaveChanges()
命令之前,我重置表的自增计数器:
Entities.Database.ExecuteSqlCommand(String.Format(“DBCC CHECKIDENT([TableNameHere],RESEED,{0})”,newObject.Id-1)); Entities.YourTable.Add(newObject); Entities.SaveChanges();
这意味着每次添加后都需要应用.SaveChanges()
- 但至少它可以工作!
嘿,你的解决方案适用于更新目的,但我这边现在出现了一个问题,它只从主键0开始添加第一条记录。
救命稻草,修改列的解决方案并不理想,因为你需要两次更新生产服务器。这个方法非常完美。只需记住,当你知道你将插入第一条记录时,移除-1
。
为什么第一行插入时ID不正确?
如果插入代码可能同时运行(例如典型的网站的一部分),请确保将SQL命令和行添加包装在事务中。否则,偶尔,你的应用程序会认为新对象具有一个ID,而SQL Server却存储了另一个ID。调试起来非常有趣!
在使用EF时,如何将上述三个命令包装在事务中?
如何强制实体框架插入标识列?
有时候,在使用Entity Framework进行插入操作时,我们希望手动指定标识列的值。然而,默认情况下,Entity Framework会自动为标识列生成值,而不接受手动指定。
解决这个问题的方法是使用事务和执行原始SQL语句。下面是一种解决方案:
1. 首先,我们需要创建一个数据上下文实例,并开始一个事务:
using (var dataContext = new DataModelContainer()) using (var transaction = dataContext.Database.BeginTransaction()) { // 在事务中进行操作 }
2. 然后,我们创建一个新的实体对象,并手动指定标识列的值:
var user = new User() { ID = id, Name = "John" };
3. 接下来,我们使用ExecuteSqlCommand
方法执行原始SQL语句,将IDENTITY_INSERT
设置为ON
,以允许手动插入标识列的值:
dataContext.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [dbo].[User] ON");
4. 然后,我们将实体对象添加到数据上下文中,并调用SaveChanges
方法保存更改:
dataContext.User.Add(user); dataContext.SaveChanges();
5. 最后,我们再次使用ExecuteSqlCommand
方法将IDENTITY_INSERT
设置为OFF
,以关闭手动插入标识列的功能:
dataContext.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [dbo].[User] OFF");
6. 最后,我们提交事务,完成操作:
transaction.Commit();
需要注意的是,如果我们在模型设计中将标识列的StoreGeneratedPattern
属性设置为None
,则可以避免出现错误。但这样做会导致无法使用正常方式(即不手动指定标识列的值)插入对象。
总结起来,以上方法可以解决Entity Framework不插入标识列的问题。需要注意的是,这种方法只是强制插入标识列的值,而不是解决Entity Framework不插入标识列的问题。同时,我们还需要注意事务的使用和SQL语句的执行方法的选择。
如何强制实体框架插入标识列?
问题原因:实体框架默认情况下不会自动插入标识列,需要手动设置。
解决方法:
1. 使用ObjectContext.ExecuteStoreCommand
方法来执行SQL命令,可以绕过实体框架的中间层。
2. 在执行插入操作之前,使用context.ExecuteStoreCommand("SET IDENTITY_INSERT [dbo].[MyUser] ON");
命令告诉数据库开启标识列插入。
3. 如果使用Code First方法,需要在OnModelCreating
方法中使用Property(obj => obj.MyUserId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None).HasColumnName("MyUserId");
命令告诉实体框架该列不是由数据库生成的。
4. 如果需要在OnModelCreating
方法执行之后告诉实体框架该信息,则需要创建一个专门用于执行标识列插入的实体,并在OnModelCreating
方法中进行配置。
5. 如果使用“数据库优先”模式,则可以在设计器中右键点击列,打开属性窗口,将[StoreGeneratedPattern]
设置为[none]
。
以上是解决问题的方法,希望能对你有所帮助!