C# 实体框架 - 在事务中的“SaveChanges”之前检索 ID
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17523568/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Entity Framework - retrieve ID before 'SaveChanges' inside a transaction
提问by user1948635
In Entity Framework - Is there any way to retrieve a newly created ID (identity) inside a transaction before calling 'SaveChanges'?
在实体框架中 - 有没有办法在调用“SaveChanges”之前在事务中检索新创建的 ID(身份)?
I need the ID for a second insert, however it is always returned as 0...
我需要第二次插入的 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();
采纳答案by zmbq
The ID is generated by the database after the row is inserted to the table. You can't ask the database what that value is going to be before the row is inserted.
ID 是在行插入表后由数据库生成的。您不能在插入行之前询问数据库该值将是什么。
You have two ways around this - the easiest would be to call SaveChanges. Since you are inside a transaction, you can roll back in case there's a problem after you get the ID.
您有两种方法可以解决这个问题 - 最简单的方法是调用SaveChanges. 由于您处于事务内部,因此您可以在获得 ID 后在出现问题时回滚。
The second way would be not to use the database's built in IDENTITYfields, but rather implement them yourself. This can be very useful when you have a lot of bulk insert operations, but it comes with a price - it's not trivial to implement.
第二种方法不是使用数据库的内置IDENTITY字段,而是自己实现它们。当您有大量批量插入操作时,这可能非常有用,但它是有代价的 - 实现起来并不容易。
EDIT: SQL Server 2012 has a built-in SEQUENCE type that can be used instead of an IDENTITY column, no need to implement it yourself.
编辑:SQL Server 2012 有一个内置的 SEQUENCE 类型,可以用来代替 IDENTITY 列,不需要自己实现。
回答by SeriousM
@zmbq is right, you can only get the id after calling save changes.
@zmbq 是对的,你只能在调用保存更改后才能获取 id。
My suggestion is that you should NOT rely on the generated ID's of the database. The database should only a detail of your application, not an integral and unchangeable part.
我的建议是您不应该依赖数据库的生成 ID。数据库应该只是你应用程序的一个细节,而不是一个不可分割的和不可更改的部分。
If you can't get around that issue use a GUID as an identifier due it's uniqueness. MSSQL supports GUID as a native column type and it's fast (though not faster than INT.).
如果您无法解决该问题,请使用 GUID 作为标识符,因为它具有唯一性。MSSQL 支持 GUID 作为本机列类型,而且速度很快(虽然不比 INT 快)。
Cheers
干杯
回答by Armen
If your tblTest entity is connected to other entities that you want to attach, you don't need to have the Id to create the relation. Lets say tblTest is attached to anotherTest object, it the way that in anotherTest object you have tblTest object and tblTestId properties, in that case you can have this code:
如果您的 tblTest 实体连接到您要附加的其他实体,则您不需要拥有 Id 来创建关系。假设 tblTest 附加到 anotherTest 对象,就像在 anotherTest 对象中您拥有 tblTest 对象和 tblTestId 属性一样,在这种情况下,您可以使用以下代码:
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);
anotherTest.tblTest = entity;
....
}
}
After submitting the relation would be created and you don't need to be worry about Ids and etc.
提交后将创建关系,您无需担心 Id 等。
回答by B12Toaster
As others have already pointed out, you have no access to the increment value generated by the database before saveChanges()was called – however, if you are only interested in the idas a means to make a connection to another entity (e.g. in the same transaction) then you can also rely on temporary ids assigned by EF Core:
正如其他人已经指出的那样,您无法访问在saveChanges()调用之前由数据库生成的增量值- 但是,如果您只对将其id作为与另一个实体建立连接(例如在同一事务中)的一种方式感兴趣,那么您还可以依赖EF Core 分配的临时 ID:
Depending on the database provider being used, values may be generated client side by EF or in the database. If the value is generated by the database, then EF may assign a temporary value when you add the entity to the context. This temporary value will then be replaced by the database generated value during SaveChanges().
根据所使用的数据库提供程序,值可能由 EF 客户端或在数据库中生成。如果该值是由数据库生成的,那么当您将实体添加到上下文时,EF 可能会分配一个临时值。这个临时值将在 SaveChanges() 期间被数据库生成的值替换。
Here is an example to demonstrate how this works. Say MyEntityis referenced by MyOtherEntityvia property MyEntityIdwhich needs to be assigned before saveChangesis called.
下面是一个示例来演示这是如何工作的。SayMyEntity由MyOtherEntityvia 属性引用,MyEntityId该属性需要在saveChanges调用之前分配。
var x = new MyEntity(); // x.Id = 0
dbContext.Add(x); // x.Id = -2147482624 <-- EF Core generated id
var y = new MyOtherEntity(); // y.Id = 0
dbContext.Add(y); // y.Id = -2147482623 <-- EF Core generated id
y.MyEntityId = x.Id; // y.MyEntityId = -2147482624
dbContext.SaveChangesAsync();
Debug.WriteLine(x.Id); // 1261 <- EF Core replaced temp id with "real" id
Debug.WriteLine(y.MyEntityId); // 1261 <- reference also adjusted by EF Core
The above also works when assigning references via navigational properties, i.e. y.MyEntity = xinstead of y.MyEntityId = x.Id
以上也适用于通过导航属性分配引用,即y.MyEntity = x代替y.MyEntityId = x.Id
回答by Hamza Khanzada
A simple work around for this would be
一个简单的解决方法是
var ParentRecord = new ParentTable () {
SomeProperty = "Some Value",
AnotherProperty = "Another Property Value"
};
ParentRecord.ChildTable.Add(new ChildTable () {
ChildTableProperty = "Some Value",
ChildTableAnotherProperty = "Some Another Value"
});
db.ParentTable.Add(ParentRecord);
db.SaveChanges();
Where ParentTableand ChildTableare two tables connected with Foregin key.
WhereParentTable和ChildTable是与 Foregin 键连接的两个表。

