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

标签 entity-framework asp.net-mvc-4 repository-pattern unit-of-work savechanges

如果这看起来像是一个重复的问题,请提前致歉。 This question是我能找到的最接近的,但它并没有真正解决我面临的问题。

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

我的工作单元类实现了 IDisposable 并包含了我的 DbContext 派生对象上下文类的单个实例,以及许多存储库,每个存储库都派生来自公开所有常用存储库功能的通用基本存储库类。

对于每个 HTTP 请求,Ninject 创建一个 Unit of Work 类的实例并将其注入(inject) Controller ,并在请求完成时自动处理它。

由于 EF5 抽象出数据存储,而 Ninject 管理对象上下文的生命周期,这似乎是使用代码访问内存中实体对象而无需显式管理其持久性的完美方式。换句话说,为了实现最佳的关注点分离,我设想我的 Controller 操作方法能够使用和修改存储库数据,而无需在之后显式调用 SaveChanges

我第一次(天真地)尝试实现这个想法是在每个修改数据的存储库基类方法中调用 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 或者让你所有的 Controller 都继承自 BaseController 类并处理 SaveChanges 在里面。

无论如何 UnitOfWork 应该总是有 SaveChanges 方法。

关于entity-framework - Entity Framework 5 工作单元模式——我应该在哪里调用 SaveChanges?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13787289/

相关文章:

asp.net-mvc-3 - Elmah 不发送电子邮件

asp.net-mvc-4 - ClaimsAuthorizationManager 从数据库中提取策略

c# - ASP.NET MVC4网页异步FTP上传

c# - N 层存储库 POCO - 聚合?

c# - 用泛型抽象一个类

c# - 如何在 Entity Framework 中获取列的默认值

design-patterns - 存储库模式和开销..?

c# - ASP.NET MVC 的最佳存储库模式

entity-framework - Entity Framework 4.1 代码首先 CREATE DATABASE 权限在数据库 'master' 中被拒绝

entity-framework - 在 Azure 上使用 Entity Framework Code First 迁移更改 PK 数据类型时出现问题