entity-framework – Entity Framework 5工作单元模式 – 我应该在哪里调用SaveChanges?

如果这似乎是一个重复的问题,请提前道歉. This question是我能找到的最接近的,但它并没有真正解决我所面临的问题.

我在ASP.NET MVC4应用程序中使用Entity Framework 5并尝试实现工作单元模式.

我的工作单元类实现了Idisposable,并包含我的DbContext派生对象上下文类的单个实例,以及许多存储库,每个存储库都派生自一个公共基本存储库类,它公开了所有常见的存储库功能.

对于每个HTTP请求,Ninject创建Unit of Work类的单个实例并将其注入控制器,并在请求完成时自动处理它.

由于EF5抽象出数据存储并且Ninject管理对象上下文的生命周期,因此它似乎是使用代码访问内存中实体对象而不需要明确管理其持久性的完美方式.换句话说,为了最佳地分离关注点,我设想我的控制器操作方法能够使用和修改存储库数据,而无需事后显式调用SaveChanges.

我实现这个想法的第一次(naiive)尝试在每个修改数据的存储库基类方法调用了SaveChanges.当然,我很快就意识到这不是性能优化的(特别是在对同一方法进行多次连续调用时),也不适应动作方法直接修改从存储库检索的对象的属性的情况.

因此,我改进了我的设计,以消除对SaveChanges的这些过早调用,并在处理Unit of Work实例时用单个调用替换它们.这似乎是MVC中工作单元模式最干净的实现,因为工作单元自然是作用于请求的.

不幸的是,在构建了这个概念后,我发现了它的致命缺陷 – 在DbContext中添加删除的对象是not reflected,even locally,直到调用了SaveChanges.

那么,您对消费代码应该能够使用对象而不明确地持久化它的想法有何看法?而且,如果这个想法似乎有效,那么用EF5实现它的最佳方法是什么?

非常感谢你的建议,

蒂姆

更新:根据@ Wahid的回复,我在下面添加了一些测试代码,其中显示了消费代码显式调用SaveChanges所必需的一些情况:

var unitOfWork = _kernel.Get<IUnitOfWork>();
var terms = unitOfWork.Terms.Entities;

// Purge the table so as to start with a kNown state 
foreach (var term in terms)
{
    terms.Remove(term);
}

unitOfWork.SaveChanges();

Assert.AreEqual(0,terms.Count());

// Verify that additions are not even reflected locally until committed.
var created = new Term { Pattern = "Test" };
terms.Add(created);
Assert.AreEqual(0,terms.Count());

// Verify that additions are reflected locally once committed.
unitOfWork.SaveChanges();
Assert.AreEqual(1,terms.Count());

// Verify that property modifications to entities are reflected locally immediately 
created.Pattern = "Test2";
var another = terms.Single(term => term.Id == created.Id);
Assert.AreEqual("Test2",another.Pattern);
Assert.True(ReferenceEquals(created,another));

// Verify that queries against property changes fail until committed
Assert.IsNull(terms.FirstOrDefault(term => term.Pattern == "Test2"));

// Verify that queries against property changes work once committed
unitOfWork.SaveChanges();
Assert.NotNull(terms.FirstOrDefault(term => term.Pattern == "Test2"));

// Verify that deletions are not even reflected locally until committed.
terms.Remove(created);
Assert.AreEqual(1,terms.Count());

// Verify that additions are reflected locally once committed.
unitOfWork.SaveChanges();
Assert.AreEqual(0,terms.Count());

解决方法

首先,SaveChanges根本不应该存在于存储库中.因为这会导致您失去UnitOfWork的好处.

其次,您需要创建一种特殊方法来保存UnitOfWork中的更改.

如果你想自动调用这个方法,那么你可以使用一些其他的解决方案,比如ActionFilter,或者让你的所有控制器都继承自BaseController类并处理它中的SaveChanges.

无论如何,UnitOfWork应始终具有SaveChanges方法.

相关文章

### 创建一个gRPC服务项目(grpc服务端)和一个 webapi项目(...
一、SiganlR 使用的协议类型 1.websocket即时通讯协议 2.Ser...
.Net 6 WebApi 项目 在Linux系统上 打包成Docker镜像,发布为...
一、 PD简介PowerDesigner 是一个集所有现代建模技术于一身的...
一、存储过程 存储过程就像数据库中运行的方法(函数) 优点:...
一、Ueditor的下载 1、百度编辑器下载地址:http://ueditor....