繁体   English   中英

将 LINQ 扩展到 Nhibernate 提供程序,并结合动态 LINQ 问题

[英]Extending LINQ to Nhibernate provider, in combination with Dynamic LINQ problem

我正在使用 NHibernate 3.1.0 并且我正在尝试通过使用BaseHqlGeneratorForMethod并扩展DefaultLinqToHqlGeneratorsRegistry来扩展 LINQ 提供程序,如Fabio 的帖子中所述。

例如,为了支持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 库(在此 Scott Guthrie 的帖子中讨论)结合使用时,就会出现问题,如下所示:

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

这会导致NotSupportedException带有“ System.String ToString() ”消息(这与我在实现上述类之前通过 static 查询得到的消息完全相同)。 此异常的来源为“ NHibernate ”,StackTrace 位于“ NHibernate.Linq.VisitorExpression.HqlGeneratorExpressionExpression .

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

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

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

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

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

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

由于您已确定 static 表达式运行良好,因此问题在于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

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

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

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM