简体   繁体   English

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

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

I'm using NHibernate 3.1.0 and I'm trying to extend the LINQ provider by using BaseHqlGeneratorForMethod and extending the DefaultLinqToHqlGeneratorsRegistry as explained in Fabio's post .我正在使用 NHibernate 3.1.0 并且我正在尝试通过使用BaseHqlGeneratorForMethod并扩展DefaultLinqToHqlGeneratorsRegistry来扩展 LINQ 提供程序,如Fabio 的帖子中所述。

For example, to support ToString() I've created a ToStringGenerator as below.例如,为了支持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));
    }
}

and I have registered using我已经注册使用

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

etc. So far this works for "static" queries, I can use it like this:等到目前为止,这适用于“静态”查询,我可以像这样使用它:

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

This translates correctly to its SQL counterpart (using SQL Server 2008)这可以正确转换为 SQL 对应物(使用 SQL Server 2008)

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

The problem arises when I try to use it in combination with Microsoft Dynamic LINQ library (discussed in this Scott Guthrie's post ) like this:当我尝试将它与 Microsoft Dynamic LINQ 库(在此 Scott Guthrie 的帖子中讨论)结合使用时,就会出现问题,如下所示:

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

This results in a NotSupportedException with a message of " System.String ToString() " (which was the exact same messages I was getting with the static queries before implementing the classes mentioned above).这会导致NotSupportedException带有“ System.String ToString() ”消息(这与我在实现上述类之前通过 static 查询得到的消息完全相同)。 This exception is being thrown with a source of " NHibernate " and with the StackTrace at " at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitMethodCallExpression(MethodCallExpression expression) ".此异常的来源为“ NHibernate ”,StackTrace 位于“ NHibernate.Linq.VisitorExpression.HqlGeneratorExpressionExpression .

So what am I missing here?那么我在这里缺少什么? What have I done wrong, or what needs to be done to support this scenario?我做错了什么,或者需要做什么来支持这种情况?

I had the same problem and fixed it.我遇到了同样的问题并修复了它。
At first I want to thank murki for providing the information which got me on my way!首先,我要感谢 murki 提供了让我上路的信息!

The answer lies partly in Fabio's post.答案部分在于法比奥的帖子。 To solve this issue you have to use the RegisterGenerator instead of the Merge method in the CustomLinqToHqlGeneratorsRegistry constructor.要解决此问题,您必须在CustomLinqToHqlGeneratorsRegistry构造函数中使用RegisterGenerator而不是Merge方法。 My implementation of the CustomLinqToHqlGeneratorsRegistry class is as follows:我对CustomLinqToHqlGeneratorsRegistry class 的实现如下:

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

There are two, well defined, separate stages here:这里有两个定义明确的独立阶段:

  1. Converting the dynamic (string) query into a static expression (done by the Dynamic Linq library)将动态(字符串)查询转换为 static 表达式(由 Dynamic Linq 库完成)
  2. Parsing that into an HqlTree, then executing (done by NHibernate)将其解析为 HqlTree,然后执行(由 NHibernate 完成)

Since you have determined that a static expression works well, the problem lies in 1.由于您已确定 static 表达式运行良好,因此问题在于1。

What happens if you do the following?如果您执行以下操作会发生什么?

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

If it fails, you'll have confirmed it's a problem with Dynamic Linq alone (ie it doesn't support the expression you're feeding it), so you'll have to dig into it and patch it.如果它失败了,您将确认这是 Dynamic Linq 单独的问题(即它不支持您输入的表达式),因此您必须深入研究并修补它。

Semi-related: the ToStringGenerator looks useful;半相关: ToStringGenerator看起来很有用; could you submit a patch for NHibernate?你能为 NHibernate 提交补丁吗? http://jira.nhforge.org http://jira.nhforge.org

Supposing the property Id of the class Project it's an Int32 try registering the corresponding Int32.ToString() method in your ToStringGenerator class.假设 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