具有多表插入的EntityFramework事务回滚

时间:2013-11-06 22:52:25

标签: c# sql sql-server entity-framework transactions

问题:我需要在多表插入中获取身份,我需要在实体框架中包含事务支持。

我有两个(伪通用)对象,带有相应的表,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

2 个答案:

答案 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的回答,那说你通常不需要手动执行此操作。

相关问题