c# - 是否可以在 NHibnernate IQueryable 中按类类型排序

标签 c# nhibernate iqueryable linq-to-nhibernate

可以使用特殊关键字 class 在 HQL 和 ICriteria 查询中按类类型排序。

criteria.AddOrder("s.class", true);

这个关键字可以用在 IQueryable OrderBy 中吗?这似乎只适用于属性表达式,不支持 .GetType()。

最佳答案

Quick&Dirty 建议

肮脏的黑客可能会奏效。根据我的经验,linq2NH 确实将可查询对象转换为 HQL 而无需太多检查(请参阅 this question 以了解其“技巧”示例代码中的示例案例)。所以你可以添加一个虚拟的而不是映射的 public virtual string @class { get;放; 基础实体上的属性,然后按它排序。

session.Query<YourBaseEntityType>().OrderBy(e => e.@class);

对其进行测试,它很可能会“直截了本地”转换为有效的 HQL 查询。当然,它很丑,可能会在任何 NH 版本升级时崩溃,...

(@ 是必需的,因为 class 是 C# 中的保留字。使用 @ 作为前缀告诉编译器它只是一个名称,不是 class 关键字。)

更清洁的建议

更简洁的方法是 extend linq2NH 用于在您的实体上支持 Class() 方法。 (在 this answer to another question 上找到的博文。编辑:这是另一个有趣的 implementation example on SO,这是一个 list of links,它提供了更多关于 可扩展性的信息。)

根据您的情况调整上面“扩展”博客文章的链接,它应该类似于以下步骤。

首先,您需要一个可在您的实体上使用的扩展方法。像这样的东西:

public static class YourLinqExtensions
{
    public static string Class(this YourEntityBaseClass source)
    { 
        // .Net runtime implementation just in case, useless in linq2nhib case
        return source == null ? null : source.GetType().Name;
    }
}

然后,实现它的HQL翻译:

public class ClassGenerator : NHibernate.Linq.Functions.BaseHqlGeneratorForMethod
{
    public ClassGenerator()
    {
        SupportedMethods = new[]
        {
            NHibernate.Linq.ReflectionHelper.GetMethod(
                () => YourLinqExtensions.Class(null))
        };
    }

    public override NHibernate.Hql.Ast.HqlTreeNode BuildHql(MethodInfo method, 
        Expression targetObject,
        ReadOnlyCollection<Expression> arguments,
        NHibernate.Hql.Ast.HqlTreeBuilder treeBuilder,
        NHibernate.Linq.Visitors.IHqlExpressionVisitor visitor)
    {
        return treeBuilder.Dot(
            // using NHibernate.Hql.Ast; required for .AsExpression() to be found
            // at compile time.
            visitor.Visit(arguments[0]).AsExpression(),
            // Below 'Class' method is not 'YourLinqExtensions.Class' extension
            // method. It is natively available on HqlTreeBuilder.
            treeBuilder.Class());
    }
}

使用生成器扩展默认的 linq2NH 注册表:

public class YourLinqToHqlGeneratorsRegistry:
    NHibernate.Linq.Functions.DefaultLinqToHqlGeneratorsRegistry
{
    public YourLinqToHqlGeneratorsRegistry()
    {
        // using NHibernate.Linq.Functions; required for .Merge() to be found
        // at compile time.
        this.Merge(new ClassGenerator());
    }
}

并配置 NH 以使用您的新注册表。对于 hibernate.cfg.xml,它应该类似于在 session-factory 节点下添加以下 property 节点:

<property name="linqtohql.generatorsregistry">YourNameSpace.YourLinqToHqlGeneratorsRegistry, YourAssemblyName</property>

用法:

session.Query<YourBaseEntityType>().OrderBy(e => e.Class());

(按照我阐述所有这些的方式,它至少应该可以编译,但它完全没有经过测试。编辑:现在它已经过测试。)

关于c# - 是否可以在 NHibnernate IQueryable 中按类类型排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35488353/

相关文章:

c# - 将日期时间值插入 SQL Server 数据库

c# - 删除标题时将相同的 CSV append 在一起

c# - PdfSharp:动态生成文档

c# - 遍历 NHibernate 实体的 IQueryable 时出现消息 "plan b"的 Antlr 异常

asp.net-mvc - 如何修复NHibernate延迟加载错误 "no session or session was closed"?

c# - 在 IQueryable 上执行文本 SQL 查询

c# - 转换表情

c# - 出现问题时如何引发异常?

带有投影和计数错误的 NHibernate Linq 查询

c# - NHibernate - 问号而不是查询中的值