【问题标题】:Extending LINQ to Nhibernate provider, in combination with Dynamic LINQ problem将 LINQ 扩展到 Nhibernate 提供程序,并结合动态 LINQ 问题
【发布时间】:2011-06-07 15:46:07
【问题描述】:

我正在使用 NHibernate 3.1.0,我正在尝试通过使用 BaseHqlGeneratorForMethod 和扩展 DefaultLinqToHqlGeneratorsRegistry 来扩展 LINQ 提供程序,如 Fabio's post 中所述。

例如,为了支持ToString(),我创建了一个ToStringGenerator,如下所示。

internal class ToStringGenerator : BaseHqlGeneratorForMethod
{
    public ToStringGenerator()
    {
        SupportedMethods = new[]
            {
                ReflectionHelper.GetMethodDefinition<object>(x => x.ToString())
            };
    }

    public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
    {
        return treeBuilder.Cast(visitor.Visit(targetObject).AsExpression(), typeof(string));
    }
}

我已经注册了

internal class CustomLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
{
    public CustomLinqToHqlGeneratorsRegistry()
    {
        this.Merge(new ToStringGenerator());
    }
}

等等。到目前为止,这适用于“静态”查询,我可以像这样使用它:

var results = mSession.Query<Project>();
string pId = "1";
results = results.Where(p => p.Id.ToString().Contains(pId));

这会正确转换为对应的 SQL(使用 SQL Server 2008)

where cast(project0_.Id as NVARCHAR(255)) like (''%''+@p0+''%'')

当我尝试将它与 Microsoft Dynamic LINQ 库(在 this Scott Guthrie's post 中讨论)结合使用时会出现问题,如下所示:

var results = mSession.Query<Project>();
string pId = "1";
results = results.Where("Id.ToString().Contains(@0)", pId);

这会导致 NotSupportedException 消息为“System.String ToString()”(这与我在实施之前使用静态查询得到的消息完全相同上面提到的类)。此异常的来源为“NHibernate”,StackTrace 位于“at NHibernate.Linq.Visitor.HqlGeneratorExpressionTreeVisitor.VisitMethodCallExpression(MethodCallExpression expression)”。 p>

那么我在这里错过了什么?我做错了什么,或者需要做什么来支持这种情况?

【问题讨论】:

    标签: c# .net linq nhibernate linq-to-nhibernate


    【解决方案1】:

    我遇到了同样的问题并修复了它。
    首先,我要感谢 murki 提供的信息,让我顺利上路!

    答案部分在于 Fabio 的帖子。要解决此问题,您必须在 CustomLinqToHqlGeneratorsRegistry 构造函数中使用 RegisterGenerator 而不是 Merge 方法。我对CustomLinqToHqlGeneratorsRegistry 类的实现如下:

    public class CustomLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
    {
        public CustomLinqToHqlGeneratorsRegistry()
            : base()
        {
            MethodInfo toStringMethod = ReflectionHelper.GetMethodDefinition<int>(x => x.ToString());
            RegisterGenerator(toStringMethod, new ToStringGenerator());
        }
    }
    

    【讨论】:

    • 这听起来像是 Merge 实现中的一个错误。
    【解决方案2】:

    这里有两个定义明确的独立阶段:

    1. 将动态(字符串)查询转换为静态表达式(由 Dynamic Linq 库完成)
    2. 将其解析为 HqlTree,然后执行(由 NHibernate 完成)

    既然你已经确定静态表达式效果很好,那么问题就出在1.

    如果您执行以下操作会发生什么?

    var results = Enumerable.Empty<Project>().AsQueryable();
    string pId = "1";
    results = results.Where("Id.ToString().Contains(@0)", pId);
    

    如果失败,您将确认仅 Dynamic Linq 存在问题(即它不支持您输入的表达式),因此您必须深入研究它并修补它。

    半相关:ToStringGenerator 看起来很有用;你能为NHibernate提交一个补丁吗? http://jira.nhforge.org

    【讨论】:

    • 感谢您的回答。我已经完成了您的建议并且查询工作正常(我的意思是它不会产生任何结果,但查询中的表达式已正确生成)。我注意到现在比较这两个查询的是,静态表达式使用 Expression.Constant 和变量 (pId) 值,而动态表达式直接使用字符串值。您认为这可能与问题有关吗?
    • @murki:是的,可能是相关的。高阻抗表达式树在支持小的变化方面非常脆弱。现在,鉴于此,您有两条路径:修补 Dynamic Linq 以发出 Expression.Constant,或修补 NHibernate 以支持 Dynamic Linq 发出的用法。
    【解决方案3】:

    假设Project 类的属性IdInt32,尝试在ToStringGenerator 类中注册相应的Int32.ToString() 方法。

    ...
    public ToStringGenerator()
    {
        SupportedMethods = new[]
            {
                ReflectionHelper.GetMethodDefinition<object>(x => x.ToString()),
                ReflectionHelper.GetMethodDefinition<int>(x => x.ToString()),
            };
    }
    ...
    

    【讨论】:

    • 是的,它是一个 Int32,但我之前实际上已经尝试过 - 这可能是另一个问题的主题,但是:1)如果我只放 object 和 int 我的错误没有任何变化,2 ) 如果我开始放置更多数据类型(例如 DateTime),它会在构建 SessionFactory 时引发 NhibernateException,并显示错误“已添加具有相同键的项目”。
    • 好的,谢谢。经过一番调查,NHibernate 3.2 仍处于 beta 版本,将在 Linq 中内置 ToString 支持。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-22
    • 1970-01-01
    • 2013-07-09
    相关资源
    最近更新 更多