存储库/ IQueryable的/查询对象 [英] Repository / IQueryable / Query Object

查看:174
本文介绍了存储库/ IQueryable的/查询对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我建立一个资料库,我已经在很多地方看到2个原因不暴露IQueryable的库外。



1)首先是因为不同的LINQ提供可以表现不同,这种差异应包含的存储库中。



2)第二个是为了防止服务水平的开发人员修改数据库查询,这样一不小心会导致性能的问题。



我猜问题2只能通过保持库中的所有查询逻辑,不允许任何形式的外部查询大楼预防吗?但是,这似乎有点不切实际了我。



第1期似乎通过使用数据对象模式来解决。



公开的IEnumerable< T> FindBy(查询的查询)



我的问题是,为什么我不只是传递一个lambda表达式,因为这是提供独立的,会出现为我提供相同的功能为查询对象,分离同级别?



公开的IEnumerable< T> FindBy(表达式来; Func键< T,BOOL>>谓语)



有什么理由不这样做呢?它打破一些规则?最佳做法? ?我应该知道


解决方案

就返回的IQueryable< T>



在你写的代码库另一位,你会显著从阅读Ayende的文章中获益的架构设计在Doom的坑 - 存储库抽象层

你的做法是,毫无疑问,加入显著不必要的复杂性。



所有的其他的问题在代码排序依据LAMBDA的泛型列表没有做其他面膜相比现有的有效的API与任何东西不必要的和不熟悉的抽象概念。



关于你提到的两个问题,




  1. LINQ提供者的行为不同,但只要你是通过谓词可以通过LINQ提供程序进行处理,这是无关紧要的。否则,你还是会遇到同样的问题,因为你传递一个表达式,它被传递到的IQueryable 最终反正。如果 IQueryProvider 的实施无法处理您的谓语,那么就无法处理您的谓语。 (您可以随时调用了ToList()如果您需要评估之前,进一步的过滤不能被翻译)。


  2. <利>

    修改的查询可能导致性能的问题,但它更容易暴露得多所需的功能。此外,通过一次最佳LINQ查询所产生的性能问题可能比通过拉动更大量记录所产生的性能问题显著少有害比你以避免暴露在 IQueryable的或通过抽象,实际上并不做任何事情的臃肿水平系统过滤的任何数据访问逻辑(第一个威胁更有显著)。一般情况下,这不会是一个问题,因为大多数领先的LINQ提供者将在翻译过程中优化您的查询逻辑。




如果您想从前端隐藏你的查询逻辑,那么不要尝试制作一个通用的存储库。封装与实际业务的具体方法查询。现在,我可能会误会,但我假设你的存储库模式的使用是由领域驱动设计的启发。如果是这样的话,那么使用存储库的原因是为了让你创建一个持久性的无知域中的一个主要专注于域模型。但是,使用这种通用的存储库并没有做更多的不是从更改语义创建,读取,更新删除查找添加删除保存。没有内嵌有没有真正的商业知识。



考虑一个

 接口的意义(和可用性)IPersonRepository 
{
的人GetById(INT ID);
IEnumerable的<&人GT; FindByName(串名字,字符串的lastName);
}



对比

 接口IRepository< T> {
IEnumerable的< T> FindBy(查询< T>查询);
}



此外,可你实际上指向一个好处是用了 IRepository< T> 在所有(而不是一个的IQueryable< T> )?



此外,考虑到与通用的方法,你实际上并没有封装查询逻辑可言。你最终会在外部构建它,这将导致更多的额外不必要的代码。



*有关建议不要使用资源的另一个音符的IQueryable< ; T> ,在于它是值得看看他们的出版日期。曾经有一个LINQ提供程序的可用性是相当有限(早EF和LINQ到SQL)的时候。当时暴露的的IQueryable< T> 将需要一些微软ORM比较流行的替代品(LINQ到NHibernate的是早已实现)不兼容。在这个时间点上,LINQ的支持是严重的ORM的.NET库几乎无处不在


I am building a repository and I've seen in many places 2 reasons not to expose IQueryable outside the repository.

1) The first is because different LINQ providers could behave differently, and this difference should be contained within the repository.

2) The second is to prevent service level developers from modifying the database query such that it accidentally causes performance issues.

I guess issue 2 can only be prevented by keeping all query logic within the repository and not allowing any form of external query building? But that does seem a bit impractical to me.

Issue 1 would seem to be resolved by using the Data Object Pattern.

e.g. public IEnumerable<T> FindBy(Query query)

My question is, why would I not just pass a lambda expression in, as that is provider independent, would appear to provide me with the same functionality as a query object, and the same level of separation?

e.g. public IEnumerable<T> FindBy(Expression<Func<T,bool>> predicate)

Is there any reason not to do this? Does it break some rules? Best-practises? that I should know about?

解决方案

Just return an IQueryable<T>.

Before you write another bit of "repository code", you will benefit significantly from reading Ayende's article Architecting in the Pit of Doom - The Evils of the Repository Abstraction Layer

Your approach is, without a doubt, adding significant unnecessary complexity.

All of the code from the other question at Generic List of OrderBy Lambda fails to do anything other than mask an existing effective API with an unnecessary and unfamiliar abstraction.

Regarding your two concerns,

  1. LINQ providers do behave differently but as long as the predicates that you are passing can be processed by the LINQ provider, this is irrelevant. Otherwise, you will still encounter the same issue, because you are passing in an Expression, which gets passed to the IQueryable eventually anyway. If the IQueryProvider implementation can't handle your predicate, then it can't handle your predicate. (You can always call a ToList() if you need to evaluate prior to further filtering that cannot be translated).

  2. Modifying a query can cause performance issues, but it is more likely to expose much needed functionality. Furthermore, the performance issues incurred by a sub-optimal LINQ query are likely to be significantly less detrimental than the performance issues incurred by pulling a lot more records than you need in order to avoid exposing an IQueryable or by systematically filtering any data access logic through bloated levels of abstractions that don't actually do anything (the first threat is more significant). In general, this won't be an issue because most leading LINQ providers will optimize your query logic in the translation process.

If you want to hide your query logic from the front end, then don't try making a generic repository. Encapsulate the queries with actual business specific methods. Now, I may be mistaken, but I am assuming your use of the repository pattern is inspired by Domain Driven Design. If this is the case, then the reason for using a repository is to allow you to create a persistence-ignorant domain with a primary focus on the domain model. However, using this kind of a generic repository doesn't do much more than change your semantics from Create Read Update Delete to Find Add Remove Save. There isn't any real business knowledge embedded there.

Consider the meaningfulness (and usability) of an

interface IPersonRepository 
{ 
     Person GetById(int id);
     IEnumerable<Person> FindByName(string firstName, string lastName);
}

in contrast to

interface IRepository<T> { 
     IEnumerable<T> FindBy(Query<T> query);
}

Furthermore, can you actually point to a benefit to using the IRepository<T> at all (as opposed to an IQueryable<T>)?

Also, consider that with the generic approach, you are not actually encapsulating query logic at all. You end up building it externally, which is going to lead to more additional unnecessary code.

*One other note about resources that advise against using IQueryable<T>, is that it is worthwhile to look at their publication date. There was a time when the availability of LINQ providers were pretty limited (to early EF and LINQ-to-SQL). At that time exposing an IQueryable<T> would entail incompatibility with some of Microsoft ORM's more popular substitutes (LINQ-to-NHibernate has long since been implemented). At this point in time, LINQ support is practically ubiquitous in serious ORM .NET libraries

这篇关于存储库/ IQueryable的/查询对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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