2

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

所以我创建了一个名为 ContainsValueGenerator 的类,它派生自 BaseHqlGeneratorForMethod,如下所示:

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 方法实现。Hqls 语法与 ContainsKey 语法非常相似。唯一需要改变的(我猜)是,我必须使用 treebuilder.Elements(在评论中显示)而不是 treebuilder.Indices()。

这就是我卡住的地方;我无法为 ElementsExpression 提供我自己的字典。如何创建一个利用 Elements 表达式的 HqlTreeNode?

在此先感谢,罗布范帕梅尔

4

1 回答 1

1

解决方案是创建自己的 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 添加一个补丁。

于 2012-05-08T07:25:24.447 回答