2010-09-15 32 views
7

据NHProf,使用隐式事务的气馁:如何在使用存储库模式的事务中保留IQueryable <>?

http://nhprof.com/Learn/Alerts/DoNotUseImplicitTransactions

然而,从数据库中读取对象时NHibernate的LINQ返回IQueryable<>,这是懒洋洋地评估。我有一个仓库这个方法:

public IQueryable<T> GetAll<T>() 
{ 
    using (var transaction = _session.BeginTransaction()) 
    { 
     var data = _session.Linq<T>(); 
     transaction.Commit(); 
     return data; 
    } 
} 

的问题在这里是评估data之前该方法将提交事务。有没有办法使用存储库模式,并保持IQueryable<>明确的交易?或者读取操作是否可以使用隐式事务?

+4

为什么要在读操作周围进行事务? – 2010-09-15 19:44:45

+3

啊,从文章中看到:“即使我们只读数据,我们也应该使用一个事务,因为使用事务可以确保我们从数据库中获得一致的结果.NHibernate假定对数据库的所有访问都是在一个事务中完成的,强烈不鼓励在没有交易的情况下使用会话。“但是,我完全不明白为什么作者正在做出这种声明。 – 2010-09-15 19:52:37

回答

5

存储库应该而不是创建一个事务。这是一个单独的层的责任(这取决于应用程序类型)。

+0

我同意,我想你的解释为什么你认为它是一个单独的层的责任是这样的:事务边界应该由用户或其他应用程序交互的方式来定义。每个请求的Web应用程序示例,每个服务调用的服务,Windows应用程序的每个“点击一个按钮”,每个移动的游戏等等。当事务由存储库创建时,创建存储库会更困难独立于应用程序与其交互的方式,并且也可能使其难以在一般情况下使用。 – Paco 2010-09-15 22:52:47

3

我想重构这个以允许外部事务控制。除非进行调用的代码告诉它,否则存储库无法知道各种读/写调用所属工作单元的范围。考虑设置“工作单元”模式:不透露数据存储实现的具体细节,允许依赖于存储库的对象指定它们开始,中止或完成“工作单元”。

public interface IRepository 
{ 
    public UnitOfWork BeginUnitOfWork() 

    public void CommitUOW(UnitOfWork unit) 

    public void AbortUOW(UnitOfWork unit) 

    public IQueryable<T> GetAll<T>(UnitOfWork unit) 

    public List<T> GetAll<T>() 

    public void Store<T>(T theObject, UnitOfWork unit) 

    public void Store<T>(T theObject) 
} 

你的版本库可能会通过维护SQL事务,每个键到的UnitOfWork对象的私人字典实现这个(这可能是一个空的实例化类一样简单,也可以提供有关国家框架无关信息或指标)。在执行数据库操作时,您的呼叫者首先要求开始一个UoW,并且他们将获得一个令牌,用于标识他们进行数据库调用的上下文。获取令牌的对象可以将它传递给需要在同一操作上下文中执行数据库操作的其他类。工作单元将保持打开状态,直到依赖类告诉存储库已完成,允许延迟加载和原子多操作过程。

请注意,有重载不需要工作单元。在没有明确启动一个工作单元的情况下进行简单调用是可能的,也许是必要的。在这些情况下,您的Repository可以创建一个内部UOW,执行请求的操作并返回结果。然而,在这些情况下,延迟加载将是困难的或不可能的;您必须在结束内部UoW之前将整个结果集检索到列表。

1

我与迭戈在这一个 - 存储库无法知道交易范围。

我还担心返回IQueryable - 据我了解,它有很多额外的查询方法,可能很难进行单元测试。我更喜欢返回IEnumerable并在存储库方法中封装更复杂的查询。否则,您将不得不根据GetAll()的输出对各种查询进行单元测试。

+1

单元测试IQueryable的所有方法真的是你的工作吗?你不应该只是你写的单元测试代码吗? – Gabe 2010-09-15 21:02:55

+0

@Gabe:我担心的不是单元测试IQueryable,而是单元测试在无数位置使用的查询的_results_。我已经读过其他人说它是查询逻辑的生存位置,但我更喜欢像GetFulfilledOrders()这样的复杂的linq查询方法来返回相同的结果。更容易测试和更清晰。 – n8wrl 2010-09-16 11:49:47

相关问题