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

本文关键字:LINQ 结合 问题 动态 扩展到 Nhibernate 程序 | 更新日期: 2023-09-27 17:58:39

我使用的是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+''%'')

当我尝试将它与微软动态LINQ库(在Scott Guthrie的帖子中讨论过)结合使用时,问题就出现了:

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

这导致NotSupportedException,消息为"System.StringToString()"(这与我在实现上述类之前通过静态查询获得的消息完全相同)。此异常是在源为"NHibernate"并且StackTrace位于"的NHibernat.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitMethodCallExpression(MethodCallExpression表达式)处引发的。

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

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

我遇到了同样的问题并解决了它。
首先,我要感谢murki提供的信息,让我走上了我的道路<答案部分在于法比奥的帖子。要解决此问题,必须在CustomLinqToHqlGeneratorsRegistry构造函数中使用RegisterGenerator而不是Merge方法。我对CustomLinqToHqlGeneratorsRegistry类的实现如下:>

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

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

  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

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

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