在实体框架中-在调用“SaveChanges”之前,是否有办法在事务中检索新创建的ID(身份)?
我需要第二次插入的ID,但是它总是作为0返回...
ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;
objectContext.Connection.Open();
using (var transaction = objectContext.Connection.BeginTransaction())
{
foreach (tblTest entity in saveItems)
{
this.context.Entry(entity).State = System.Data.EntityState.Added;
this.context.Set<tblTest>().Add(entity);
int testId = entity.TestID;
.... Add another item using testId
}
try
{
context.SaveChanges();
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
objectContext.Connection.Close();
throw ex;
}
}
objectContext.Connection.Close();
7条答案
按热度按时间nqwrtyyt1#
ID由数据库在将行插入到表中之后生成。在插入行之前,您不能询问数据库该值是什么。
有两种方法可以解决这个问题--最简单的方法是调用
SaveChanges
,因为您是在事务内部,所以在获得ID后,如果出现问题,您可以回滚。第二种方法是不使用数据库内置的
IDENTITY
字段,而是自己实现它们。当你有很多批量插入操作时,这会非常有用,但它也有代价--实现起来并不容易。编辑:SQL Server 2012有一个内置的SEQUENCE类型,可以用来代替IDENTITY列,不需要自己实现它。
c9x0cxw02#
正如其他人已经指出的,在调用
saveChanges()
之前,您无法访问数据库生成的增量值--然而,如果您只对id
感兴趣,将其作为连接到另一个实体(例如,在同一事务中)的一种手段,那么您还可以依赖EF Core分配的临时ID:根据所使用的数据库提供程序,值可以由EF在客户端生成,也可以在数据库中生成。如果值由数据库生成,则在将实体添加到上下文时,EF可能会分配一个临时值。然后,在SaveChanges()过程中,此临时值将被数据库生成的值替换。
下面是一个例子来演示它是如何工作的,假设
MyEntity
被MyOtherEntity
通过属性MyEntityId
引用,该属性需要在调用saveChanges
之前赋值。当通过导航属性(即
y.MyEntity = x
而不是y.MyEntityId = x.Id
)分配引用时,上述方法也适用svmlkihl3#
如果你的tblTest实体连接到你想要附加的其他实体,你不需要ID来创建关系。假设tblTest被附加到另一个Test对象,就像在另一个Test对象中你有tblTest对象和tblTestId属性一样,在这种情况下你可以有下面的代码:
提交后的关系将被创建,你不需要担心的ID等。
njthzxwz4#
@zmbq是对的,调用保存changes后才能得到id。
我的建议是,你不应该依赖于生成的ID的数据库。数据库应该只是一个细节,你的应用程序,而不是一个完整的和不可更改的一部分。
如果你不能解决这个问题,使用GUID作为一个标识符,因为它的唯一性。MSSQL支持GUID作为一个本地列类型,它的速度很快(虽然没有比INT快)。
干杯
vmjh9lq95#
在调用
.SaveChanges()
之前,您可以使用Hi/Lo算法检索ID。一旦对象被添加到dbcontext中,ID就会被分配给对象。使用Fluent API的配置示例:
相关Microsoft文章的摘录:
当您在提交更改之前需要唯一键时,Hi-Lo算法非常有用。总之,Hi-Lo算法为表行分配唯一标识符,而不需要立即将行存储在数据库中。这样,您就可以立即开始使用标识符,就像常规顺序数据库ID一样。
p5cysglq6#
解决此问题的简单方法是
其中
ParentTable
和ChildTable
是用Foregin键连接的两个表。pxq42qpu7#
您可以在ChangeTracker中查找该值,如下所示:
我的设置是mysql5.7,但应该在其他环境中也工作。