我正在编写一个(另一个)实体的通用存储库,它不一定由关系数据库支持。我希望其中一个IEnumerable<T> Load<T>(...)
方法将一个通用Expression<Func<T, bool>>
谓词作为参数,该谓词为要检索的实体指定用户定义的条件。请注意,我不想向用户公开完整的IQueryable<T>
,因为我想限制底层存储对用户的公开。
在存储库由NHibernate(顺便说一句,3.1)支持的情况下,简单谓词(如x => x.Name="Mike"
)可以通过LINQ for NHibernaate(使用Where(Expression<Func<T, bool>>)
方法)"向下推"到关系数据库,当底层实体集很大并且谓词只选择一个实体时,性能会明显提高。美好的
然而,我的用户不一定知道存储库由关系数据库支持,因此谓词有时可能非常复杂(例如x => MyFunction(x.Name) == 0
),以至于LINQ to NHibernate无法为它们生成HQL。在这些情况下,我想检测LINQ生成HQL的失败,并透明地"故障转移"到加载所有实体并显式地将谓词应用于每个实体。
问题是,我无法找到可靠的方法来检测LINQ to NHibernate未能翻译谓词表达式。直接执行查询会抛出系统。NotSupportedException,这可能是由任何原因引起的,甚至是由底层的ConnectionProvider引起的。
我考虑了一下将查询执行一分为二的可能性——先翻译,然后执行——然后捕获系统。翻译过程中出现NotSupportedException。为此,我尝试了在中提出的解决方案。有人知道如何将LINQ表达式翻译为NHibernate HQL语句吗?为了在执行前翻译查询,我不得不说,我让它工作了,但它使用反射来访问内部NHibernate对象的未记录的、非公共的方法,因此它闻起来像是一个不受支持的黑客。
是否有更可靠和"官方"的方法来检测LINQ to NHibernate未能翻译表达式,或者在不执行查询的情况下翻译表达式?
我不认为有,但由于NHibernate是一个开源项目,你可以很容易地这样做:
- 获取NHibernate的源代码
- 用更具体的异常替换LINQ提供程序中的所有
NotSupportedException
(它将继承NotSupportedException
以避免不必要的中断) - 编译修改后的NHibernate并在代码中使用它
- 在代码中需要新异常的任何地方/以任何方式处理它
- 将您的修改作为补丁提交给NHibernate JIRA(不要忘记测试,否则可能不会考虑)
- 利润