C# 使用多表插入的EntityFramework事务回滚

C# 使用多表插入的EntityFramework事务回滚,c#,sql,sql-server,entity-framework,transactions,C#,Sql,Sql Server,Entity Framework,Transactions,问题:我需要在多表插入中获取标识,并且需要在实体框架中围绕它包装事务支持。 我有两个(psuedo-generic)对象,它们具有相应的表、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

问题:我需要在多表插入中获取标识,并且需要在实体框架中围绕它包装事务支持。

我有两个(psuedo-generic)对象,它们具有相应的表、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)
)
我的问题是,当我需要插入一本有新作者的新书时,我最终需要做类似的事情,如果图书插入引发了一个异常,我有一个没有书的作者,这对我的应用程序不好

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();

我浏览了一下,基本上是说不要在EntityFramework中使用事务,并建议每次操作调用SaveChanges()一次,让EF自己处理事务。我很愿意,但我需要先从表中获取身份,就像我的psuedo代码中指出的那样,问题是-您绝对需要插入作者的ID吗

您可以使用实体先使用代码或先使用db进行开发。如果您首先使用db,您将拥有.edmx文件,其中包含生成的实体、导航属性和集合。。。那么,上述关键特性的要点是什么呢?对于作者实体,由于表Book中的relationshipauthorid int references Author(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... 
类似结构也适用于代码优先;在“作者实体”中,您很可能拥有
公共虚拟ICollection图书。这本书的创作将以上述相同的方式进行

当然,您可以通过多次
context.SaveChanges()
来获取新插入实体的ID,但不应该这样做。每个
SaveChanges()
都只是向服务器发送往返广告,很可能最终会导致性能低下。如上所述,最好将ID值的管理留给实体


还有,结束这个故事。使用上述结构,EF会自动将所有内容包装到事务中的-SaveChanges()。因此,如果
Book
插入失败,
Author
插入也将撤消。

如果您确实不想在代码中使用事务,那么您可以将所有内容包装在存储过程中。但是,仅仅因为默认隔离级别是可序列化的,就没有理由不能更改它:

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();
}

也就是说,根据Dmitry的回答,您通常不需要手动执行此操作。

您在创建模型时是否在模型中包含外键列?如果是这样,当您调用SaveChanges()?Laurence时,EF不应该自动将属性映射到彼此吗。我将进一步阅读为什么交易如此可怕(我引用的其中一篇文章),但与此同时,这是有效的,我看不到它在我的世界中造成任何真正的问题。