Linq To Nhibernate:HqlTreeBuilder with Elements 如何使用

本文关键字:Elements 何使用 with HqlTreeBuilder To Nhibernate Linq | 更新日期: 2023-09-27 18:33:07

对于我正在开发的项目,我必须使用 Linq 来创建一些规范。现在我有一个字典,我必须在上面搜索值。由于 NHibernate 的默认 Linq 实现不支持 ContainsValue 函数,因此我决定创建自己的函数。

因此,我创建了一个名为ContainsValueGenerator的类,该类派生自BaseHqlForMethod,如下所示:

public class ContainsValueGenerator : BaseHqlGeneratorForMethod
{
    public ContainsValueGenerator()
    {
        SupportedMethods = new[] { ReflectionHelper.GetMethodDefinition(() => new Dictionary<object, object>().ContainsValue(null)) };
    }
    public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
    {
        //Session.CreateQuery("from Message m where 'aDictionaryValue' in elements(m.Dictionary)"); 
        HqlTreeNode hqlTreeNode = treeBuilder.Elements(); // TODO include dictionary here? 
        return treeBuilder.In(visitor.Visit(arguments[0]).AsExpression(), hqlTreeNode);
        //return treeBuilder.In(visitor.Visit(arguments[0]).AsExpression(), treeBuilder.Indices(visitor.Visit(targetObject).AsExpression())); ContainsKey Method implementation 
    }
}

我查看了Nhibernate的源代码,并采用了ContainsKey方法实现。Hqlsyntax 与 ContainsKey 语法非常相似。唯一需要改变的是(我猜)而不是树构建器。索引(),我必须使用树构建器。元素(显示在注释中)。

这就是我陷入困境的地方;我无法为元素表达式提供我自己的字典。如何创建利用元素表达式的 HqlTreeNode?

提前感谢, 罗伯·范帕梅尔

Linq To Nhibernate:HqlTreeBuilder with Elements 如何使用

解决方案是创建自己的 HqlElements 类,该类继承自 HqlExpression。事实上,它只是 HqlIndices 类的副本。

public class HqlElements : HqlExpression
{
    public HqlElements(IASTFactory factory, HqlExpression dictionary)
        : base(HqlSqlWalker.ELEMENTS, "elements", factory, dictionary)
    {
    }
}

棘手的部分是将其作为属性添加到 HqlTreeBuilder 类中。因此,您可以使用扩展方法。这包含一段丑陋的代码,用于获取带有反射的HqlTreeBuilder的工厂。

public static class HqlTreeBuilderExtensions
{
    public static HqlElements Elements(this HqlTreeBuilder treeBuilder, HqlExpression dictionary)
    {
        var factory = (IASTFactory) treeBuilder.GetType().GetField("_factory", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(treeBuilder);
        return new HqlElements(factory, dictionary);
    }
}

您的生成器现在可以更改为:

public class ContainsValueGenerator : BaseHqlGeneratorForMethod
{
    public ContainsValueGenerator()
    {
        SupportedMethods = new[] { ReflectionHelper.GetMethodDefinition(() => new Dictionary<object, object>().ContainsValue(null)) };
    }
    public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
    {
        return treeBuilder.In(visitor.Visit(arguments[0]).AsExpression(), treeBuilder.Elements(visitor.Visit(targetObject).AsExpression()));
    }
}

最好的解决方案是这段代码将它变成NHibernate本身。也许我会为此在 GitHub 上添加一个补丁。