如何在不将IQueryable暴露给应用程序其余部分的情况下编写干净的存储库? [英] How can I write a clean Repository without exposing IQueryable to the rest of my application?

查看:93
本文介绍了如何在不将IQueryable暴露给应用程序其余部分的情况下编写干净的存储库?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我已经阅读了关于SO是否将IQueryable暴露给项目其余部分的所有问题解答(请参阅此处),而我最终决定不将IQueryable暴露给我的Model.因为IQueryable与某些持久性实现相关,所以我不喜欢将自己锁定在其中的想法.同样,我不确定在调用链中的类对修改不在存储库中的实际查询的感觉如何.

So, I've read all the Q&A's here on SO regarding the subject of whether or not to expose IQueryable to the rest of your project or not (see here, and here), and I've ultimately decided that I don't want to expose IQueryable to anything but my Model. Because IQueryable is tied to certain persistence implementations I don't like the idea of locking myself into this. Similarly, I'm not sure how good I feel about classes further down the call chain modifying the actual query that aren't in the repository.

那么,有没有人对如何编写干净简洁的存储库有任何建议呢?我看到的一个问题是,我的存储库将因大量需要过滤查询的各种方法而爆炸.

So, does anyone have any suggestions for how to write a clean and concise Repository without doing this? One problem I see, is my Repository will blow up from a ton of methods for various things I need to filter my query off of.

有一堆:

IEnumerable GetProductsSinceDate(DateTime date);  
IEnumberable GetProductsByName(string name);  
IEnumberable GetProductsByID(int ID);

如果我允许传递IQueryable,那么我很容易拥有一个通用的存储库,如下所示:

If I was allowing IQueryable to be passed around I could easily have a generic repository that looked like:

public interface IRepository<T> where T : class
{
    T GetById(int id);
    IQueryable<T> GetAll();
    void InsertOnSubmit(T entity);
    void DeleteOnSubmit(T entity);
    void SubmitChanges();
}

但是,如果您不使用IQueryable,则诸如GetAll()之类的方法实际上并不实用,因为不会进行延迟评估.我不想返回10,000条记录以便以后再使用其中的10条.

However, if you aren't using IQueryable then methods like GetAll() aren't really practical since lazy evaluation won't be taking place down the line. I don't want to return 10,000 records only to use 10 of them later.

这里的答案是什么?在 Conery的MVC店面中,他创建了另一个名为服务"层的层,该层接收了来自IQueryable的结果.存储库,并负责应用各种过滤器.

What is the answer here? In Conery's MVC Storefront he created another layer called the "Service" layer which received IQueryable results from the respository and was responsible for applying various filters.

这是我应该做的还是类似的事情?我的存储库是否让IQueryable返回IQueryable,但将其隐藏在诸如GetProductByName之类的一堆过滤器类后面,从而限制了对它的访问,这些过滤器类将返回诸如IList或IEnumerable的具体类型?

Is this what I should do, or something similar? Have my repository return IQueryable but restrict access to it by hiding it behind a bunch of filter classes like GetProductByName, which will return a concrete type like IList or IEnumerable?

推荐答案

公开IQueryable是一个非常可行的解决方案,这就是目前大多数Repository实现的方式. (还包括SharpArchitecture和FubuMVC contrib.)

Exposing an IQueryable is a very viable solution and this is how most of the Repository implementations out there doing right now. (Including SharpArchitecture and FubuMVC contrib, as well.)

这是你错了:

但是,如果您不使用 IQueryable然后使用诸如GetAll()的方法 因为懒惰所以不是很实际 评估不会失败 线.我不想回来 10,000条记录仅可使用其中10条 以后.

However, if you aren't using IQueryable then methods like GetAll() aren't really practical since lazy evaluation won't be taking place down the line. I don't want to return 10,000 records only to use 10 of them later.

这不是真的.您的示例是正确的,应将GetAll()重命名为更具参考性的名称.

This is not realy true. Your example is correct and you should rename GetAll() to a more informative name.

如果您调用它,则不会返回所有项目.这就是IQueryable的目的.这个概念称为延迟加载",因为它只在枚举IQueryable时才加载数据(并发出数据库请求).

It DOESN'T return all of the items if you call it. That is what IQueryable is for. The concept is called "deferred loading", as it only loads the data (and makes database requests) when you enumerate the IQueryable.

所以,假设我有一个这样的方法:

So, let's say I have a method like this:

IQueryable<T> Retrieve() { ... }

然后,我可以这样称呼它:

Then, I can call it like this:

Repository.Retrieve<Customer>().Single(c => c.ID == myID);

这仅从数据库中检索一行.

This ONLY retrieves one row from the database.

这:

Repository.Retrieve<Customer>().Where(c => c.FirstName == "Joe").OrderBy(c => c.LastName);

这还会生成一个相应的查询,并且仅在枚举时才执行. (它从查询中生成一个表达式树,然后查询提供程序应将其转换为针对数据源的适当查询.)

This also generates a corresponding query and is only executed when you enumerate it. (It generates an expression tree from the query, and then the query provider should translate that into an appropriate query against the data source.)

您可以在MSDN上的这篇文章中了解更多信息.

You can read more about it in this MSDN article.

这篇关于如何在不将IQueryable暴露给应用程序其余部分的情况下编写干净的存储库?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆