将LINQ扩展到Nhibernate提供程序,结合Dynamic LINQ问题

时间:2011-06-07 15:46:08

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

我正在使用NHibernate 3.1.0,我正在尝试使用BaseHqlGeneratorForMethod扩展LINQ提供程序,并按照Fabio's post中的说明扩展DefaultLinqToHqlGeneratorsRegistry

例如,为了支持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 ”源代码抛出此异常,并在“ at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitMethodCallExpression(MethodCallExpression expression)”中使用StackTrace。

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

3 个答案:

答案 0 :(得分:3)

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

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

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

答案 1 :(得分:1)

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

  1. 将动态(字符串)查询转换为静态表达式(由Dynamic Linq库完成)
  2. 将其解析为HqlTree,然后执行(由NHibernate完成)
  3. 由于您已确定静态表达式运行良好,因此问题出在 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

答案 2 :(得分:0)

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

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