3

问题:我需要在多表插入中取回一个身份,并且我需要在 Entity Framework 中围绕它包装事务支持。

我有两个(伪通用)对象和对应的表,书和作者:

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 insert 引发异常,我有一个没有书的作者,这对我的应用程序不利.

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 自己处理事务。我很乐意,但我需要先从表中取回身份,就像我的伪代码和这个 SO question中所示

4

2 回答 2

5

问题是 - 你绝对需要插入作者的 ID 吗?

您可以先使用代码或先使用 db 使用 Entity 进行开发。如果您首先使用 db,您将拥有 .edmx 文件,其中包含生成的实体、导航属性和集合......那么,上面的重点是什么 - 关键功能,对于 Author 实体,您将拥有 Books 集合,这要归功于关系authorid int在您的表 Book 中引用 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... 

类似的结构也适用于代码优先;在作者实体中,您很可能会public virtual ICollection<Book> Books收藏。并且书籍的创建将以与上述相同的方式完成。

当然,您可以制作多个context.SaveChanges()来获取新插入实体的 ID - 您不应该这样做。每个SaveChanges()只是广告往返到服务器,并且可能最终会导致性能不佳。如上所述,最好将 ID 值的管理留给 Entity。

而且,要完成这个故事。使用上面的结构,EF 会自动将所有直到 SaveChanges() 的内容包装在事务中。因此,如果Book插入失败,Author插入也将被撤消。

于 2013-11-06T23:10:35.453 回答
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 的回答,您通常不需要手动执行此操作。

于 2013-11-06T23:17:07.917 回答