简体   繁体   English

如何使用存储库模式在事务中保留IQueryable <>?

[英]How do I keep an IQueryable<> within a transaction using the repository pattern?

According to NHProf, the use of implicit transactions is discouraged: 根据NHProf,不鼓励使用隐式交易:

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

However, NHibernate LINQ returns an IQueryable<> when reading objects from the database, and this is lazily evaluated. 但是,当从数据库中读取对象时,NHibernate LINQ返回IQueryable<> ,这是懒惰的评估。 I have this method in a repository: 我在存储库中有这个方法:

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

The issue here is that the method will commit the transaction before data is evaluated. 这里的问题是该方法将在评估data之前提交事务。 Is there a way to use the repository pattern and keep the IQueryable<> in an explicit transaction? 有没有办法使用存储库模式并将IQueryable<>保留在显式事务中? Or is it acceptable for read operations to use implicit transactions? 或者读取操作是否可以使用隐式事务?

The repository should not create a transaction. 这个仓库应该创建事务。 That's a responsibility of a separate layer (which depends on the application type). 这是一个单独的图层(取决于应用程序类型)的责任。

I'd refactor this to allow external transaction control. 我会重构这个以允许外部事务控制。 The Repository cannot know the scope of the unit of work that various read/write calls are a part of unless the code that makes the calls tells it. 除非进行调用的代码告诉它,否则存储库无法知道各种读/写调用所属的工作单元的范围。 Consider setting up a "unit of work" pattern: without revealing specific details of the data store implementation, allow objects that depend on Repository to specify that they are beginning, aborting or completing a "unit of work". 考虑设置“工作单元”模式:在不泄露数据存储实现的特定细节的情况下,允许依赖于存储库的对象指定它们正在开始,中止或完成“工作单元”。

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

Your Repository would probably implement this by maintaining a private Dictionary of SQL transactions, each keyed to a UnitOfWork object (this can be as simple as an empty instantiable class, or it can provide framework-agnostic information about state or metrics). 您的存储库可能通过维护一个私有的SQL事务字典来实现这一点,每个字典都键入一个UnitOfWork对象(这可以像一个空的可实例化类一样简单,或者它可以提供有关状态或度量的框架无关信息)。 When performing a DB operation, your callers will first ask to begin a UoW, and they will be given a token that they will use to identify the context within which they are making a DB call. 执行数据库操作时,您的呼叫者将首先要求开始使用UoW,并且将为他们提供一个令牌,用于识别他们进行数据库呼叫的上下文。 The object that gets the token can pass it to other classes that need to perform DB operations in the same operational context. 获取令牌的对象可以将其传递给需要在同一操作上下文中执行数据库操作的其他类。 The unit of work will remain open until the dependent class tells the Repository that it is finished, allowing lazy-loads and atomic multi-operation procedures. 工作单元将保持打开状态,直到依赖类告诉存储库它已完成,允许延迟加载和原子多操作过程。

Notice that there are overloads that do not require units of work. 请注意,存在不需要工作单元的重载。 It is possible, and perhaps necessary, to make simple calls without explicitly starting a unit of work. 在没有明确启动工作单元的情况下进行简单调用是可能的,也许是必要的。 In these cases, your Repository can create an internal UOW, perform the requested operation, and return the results. 在这些情况下,您的存储库可以创建内部UOW,执行请求的操作,并返回结果。 However, lazy-loading will be difficult or impossible in these cases; 但是,在这些情况下,延迟加载将是困难的或不可能的; you will have to retrieve the entire result set into a List before ending the internal UoW. 在结束内部UoW之前,您必须将整个结果集检索到List中。

I'm with Diego on this one - repository can't know the transaction scope. 我和Diego在这一个 - 存储库无法知道事务范围。

I also have a concern about returning IQueryable - as I understand it, it has a ton of extra query methods that might be very difficult to unit test. 我还担心返回IQueryable - 据我所知,它有大量额外的查询方法,可能很难进行单元测试。 I prefer returning IEnumerable and encapsulate more complex queries in repository methods. 我更喜欢返回IEnumerable并在存储库方法中封装更复杂的查询。 Otherwise, you'll have to unit test all kinds of variations of queries against the output of GetAll(). 否则,您将必须针对GetAll()的输出对各种查询变体进行单元测试。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用通用存储库模式按类型有条件地过滤IQueryable - How to conditionally filter IQueryable by type using generic repository pattern 如何使用工作单元和存储库模式回滚事务? - How do I rollback a transaction using Unit of Work and Repository patterns? 如何保持 IQueryable 的优势<t>在使用 ViewModel 或 DTO 而不是 ORM 生成的实体时?</t> - How do I keep the Advantages of IQueryable<T> while using ViewModels or DTOs instead of ORM generated Entities? 如何在通用扩展方法中使用字符串列名称对IQueryable应用OrderBy? - How do I apply OrderBy on an IQueryable using a string column name within a generic extension method? 如何解决IQueryable Select语句中的Union上的错误 - How do I resolve an error on Union within IQueryable Select statement 如何使用存储库模式模拟 MongoDB 数据访问层? - How do I Mock MongoDB Data Access Layer using Repository Pattern? 使用存储库模式,如何在不创建泄漏抽象的情况下引用域模型? - Using the repository pattern, how do I reference my domain models without creating a leaky abstraction? 使用存储库模式时,如何恢复数据库生成的ID? - How do I get DB generated IDs back when using repository pattern? 实体框架和存储库模式(IQueryable的问题) - Entity Framework and Repository Pattern (problem with IQueryable) 如何正确伪造IQueryable <T> 从使用Moq的存储库? - How to properly fake IQueryable<T> from Repository using Moq?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM