nHibernate HqlTreeBuilder 为 HierarchyId 实现 Linq 方法

nHibernate HqlTreeBuilder to implement Linq methods for HierarchyId

我正在考虑使用 HierarchyId 在 SQL Server 中实现 Hierarchy 数据结构,并且我需要添加可以通过 Linq 使用的扩展方法,以使用在 TSQL 中公开的 HierarchyId 方法。现在,我拥有了通过 HqlGenerator 将 Linq 方法连接到 NHibernate 的所有代码,我只是找不到构建所需 SQL 的正确代码。

例如,对于打击 Linq...

1
session.Query<Person>().Where(x=>x.Hierarchy.IsDescendantOf('/1/3/'))

我希望得到类似这样的 SQL...

1
2
3
SELECT people0_.ObjectId, people0_.Name, people0_.Hierarchy
    FROM People people0_
        WHERE people0_.Hierarchy.IsDescendantOf('/1/3/') = 1

我的问题是我无法弄清楚要在我的 BaseHqlGeneratorForMethod 类中实现的 HqlTreeBuilder 代码来完成它,因为我需要让 IsDescendantOf 方法成为列的子方法,这意味着我需要将表示层次结构列的表达式组合在我的方法调用之前立即出现的表达式与中间的点。

我认为这会起作用,但事实并非如此。有什么建议吗?

1
2
3
4
5
6
7
public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
    return treeBuilder.Equality(
            treeBuilder.Dot(visitor.Visit(arguments[0]).AsExpression(), treeBuilder.MethodCall("IsDescendantOf", new[] {visitor.Visit(arguments[1]).AsExpression()})),
            treeBuilder.Constant(1)
        );
}

我最终是这样做的......

我的代码实现

1
2
3
4
5
6
7
8
public static bool IsDescendantOf(this string childHierarchy, string parentHierarchy)
{
    //In most cases this will be translated to the SQL implementation by LINQ, but on the off chance it's used on an in memory collection, the simplest implementation
    //Is to verify that the child hierarchy starts with the hierarchy of the parent.
    //for example....
    //"/11/534/2134/".StartsWith("/11/534/") //would be TRUE
    return childHierarchy.StartsWith(parentHierarchy);
}

HqlGenerator

1
2
3
4
public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
    return treeBuilder.BooleanMethodCall("_IsDescendantOf", new[] { visitor.Visit(arguments[0]).AsExpression(), visitor.Visit(arguments[1]).AsExpression() });
}

然后你在哪里配置 nHibernate 我有这行

1
cfg.AddSqlFunction("_IsDescendantOf", new NHibernate.Dialect.Function.SQLFunctionTemplate(NHibernate.NHibernateUtil.Boolean,"?1.IsDescendantOf(?2) = 1"));

其中 cfg 是您的 NHibernate.Cfg.Configuration

的实例