问题:我需要在多表插入中获取身份,我需要在实体框架中包含事务支持。
我有两个(伪通用)对象,带有相应的表,Book和Author:
create table Author
(authorid int identity primary key,
authorname varchar(max)
)
create table Book
(bookid int identity primary key,
bookname varchar(max),
authorid int references Author(authorid)
)
我的问题是,当我需要与新作者一起插入新书时,我最终需要做这样的事情,如果Book插入引发异常我有一个没有书的作者,这是不好的对于我的申请。
context.Authors.Add(newauthor);
context.SaveChanges();
newbook.AuthorID = newauthor.ID //I can read this now because the SaveChanges() created the ID
context.Books.Add(newbook);
context.SaveChanges();
我浏览了this article,它基本上表示不使用与EntityFramework的交易,并建议每次操作调用一次SaveChanges()并让EF自己处理事务。我很乐意,但我需要首先从表格中获取身份,如我的伪代码中所示this SO question
答案 0 :(得分:5)
问题是 - 您是否绝对需要插入作者的ID?
您可以使用代码优先使用代码进行开发,也可以先使用db进行开发。如果您首先使用数据库,您将拥有带生成实体的.edmx文件,具有导航属性和集合......那么,上面的关键特征是什么,对于Author实体,您将拥有Books集合,这要归功于关系 authorid int在您的表格书中引用作者(authorid)。 因此,要向作者添加书籍,只需制作如下内容:
//Somewhere here author is created, add it to context.Authors
context.Authors.Add(newauthor);
//Somewhere here book is created, don't need to add it to context.Books; don't call SaveChanges either
newauthor.Books.Add(newbook);// And this is all you need; ID management will be done by Entity, automatically
context.SaveChanges(); // Only one call to save changes you will need
//Of course, all IDs of inserted entities will be available here...
类似的结构也将首先对代码有效;在作者实体中,您很可能会收集public virtual ICollection<Book> Books
。并且将以与上述相同的方式创建书籍。
当然,您可以使多个context.SaveChanges()
获取新插入实体的ID - 但您不应该这样做。每个SaveChanges()
只是广告往返于服务器,并且可能最终会导致性能不佳。如上所述,最好将ID值的管理留给Entity。
并完成故事。使用上面的结构,EF会自动将所有内容包装到事务中的SaveChanges()中。因此,如果Book
插入失败,Author
插入也将被撤消。
答案 1 :(得分:2)
如果您真的不想在代码中使用事务,那么您可以将所有内容包装在存储过程中。但是,仅仅因为默认隔离级别是可序列化的,所以没有理由不能更改它:
using(var scope = new TransactionScope(
TransactionScopeOption.RequiresNew,
new TransactionOptions() {
IsolationLevel = IsolationLevel.ReadCommitted
})) {
context.Authors.Add(newauthor);
context.SaveChanges();
newbook.AuthorID = newauthor.ID
context.Books.Add(newbook);
context.SaveChanges();
scope.Complete();
}
根据Dmitriy的回答,那说你通常不需要手动执行此操作。