Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/73.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 修改NHibernate查询的排序规则_Sql_Nhibernate_Collation - Fatal编程技术网

Sql 修改NHibernate查询的排序规则

Sql 修改NHibernate查询的排序规则,sql,nhibernate,collation,Sql,Nhibernate,Collation,我有一个大型ASP.NET应用程序,它使用NHibernate(v3.2.0.4000)访问SQL Server 2005作为后端数据存储。我们有多个客户,每个客户都有自己的数据库,但所有数据库都运行在同一台服务器上 快速提问: 如果不在数据库服务器或单个数据库本身上设置排序规则,或者不重新编写现有的单个NHibernate查询代码,我如何在NHibernate查询命中数据库之前,将自定义排序语句添加到NHibernate查询中(纯粹出于排序目的)? 较长的问题: 由于有一些新的国际客户,我们需

我有一个大型ASP.NET应用程序,它使用NHibernate(v3.2.0.4000)访问SQL Server 2005作为后端数据存储。我们有多个客户,每个客户都有自己的数据库,但所有数据库都运行在同一台服务器上

快速提问:
如果不在数据库服务器或单个数据库本身上设置排序规则,或者不重新编写现有的单个NHibernate查询代码,我如何在NHibernate查询命中数据库之前,将自定义排序语句添加到NHibernate查询中(纯粹出于排序目的)?

较长的问题:
由于有一些新的国际客户,我们需要支持自定义排序,以便在应用程序中进行排序。我们不能在数据库(或服务器)级别上执行此操作,因为我们在同一服务器上为每个客户托管一个单独的数据库(每个客户可能有不同的排序要求),并且在同一服务器上存在诸如TempDB等和多个不同排序的复杂性(请参阅和)

由于NHibernate在整个代码库中的使用方式不同(即HQL、ICriteria、普通SQL、QueryOver和Linq的组合),并且由于这些查询中的许多查询非常复杂和混乱,我们希望完全避免更改任何现有的NHibernate查询代码

SQL Server将允许调用在查询运行时应用特定排序规则的查询,如:
SELECT*FROM Customer ORDER BY names COLLATE Latin1\u General\u CI\u AS

我还知道NHibernate允许创建一个
拦截器
,该拦截器可以在全局或特定于会话的基础上添加到NHibernate(如图所示),允许在将SQL语句发送到SQL Server之前拦截SQL语句

似乎我可以编写一个拦截器类来截取SQL语句,但是,它只允许我捕获原始SQL语句(包括NHibernate奇怪而奇妙的字段和别名)。我不知道是否有任何方法可以清晰地解析查询的特定部分(我只需要ORDER BY子句),并在检查字段是否基于文本并允许将COLLATE语句附加到它们之后更改ORDER BY子句的各个组成部分(即各个字段)

NHibernate公开了一个
NHibernate.SqlCommand.ISqlStringVisitor
接口,该接口听起来很有前途,似乎在
EmptyInterceptor
类的
onpreparest陈述
方法中捕获的
SqlString
上运行,该方法可以被覆盖,但是,我对NHibernate的这一部分完全不熟悉,在我写这篇文章的时候,NHibernate被认为是可靠的信息来源,但现在已经关闭了(而且似乎已经关闭了好几个星期)


有人必须执行这样的任务吗?是否可以以干净且类型安全的方式构造NHibernate查询?是否有一种完全不同的方法可以实现相同的目标(考虑到无法更改数据库/服务器排序规则的相同限制)?

使用自定义投影可以相对轻松地实现这一点。以下课程是一个很好的起点:

public class OrderByWithCollate : SimpleProjection
{
    public string ColumnName { get; private set; }
    public string Collation { get; private set; }

    public OrderByWithCollate(string columnName, string collation)
    {
        ColumnName = columnName;
        Collation = collation;
    }

    public override SqlString ToGroupSqlString(
        ICriteria criteria, 
        ICriteriaQuery criteriaQuery, 
        IDictionary<string, IFilter> enabledFilters)
    {
        throw new NotImplementedException();   
    }

    public override SqlString ToSqlString(
        ICriteria criteria, 
        int position, 
        ICriteriaQuery criteriaQuery, 
        IDictionary<string, IFilter> enabledFilters)
    {
        return new SqlStringBuilder()
            .Add(ColumnName)
            .Add(" COLLATE ").Add(Collation)
            .Add(" as __collate_").ToSqlString();
    }

    public override IType[] GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuery)
    {
        return new IType[] {NHibernateUtil.String};
    }

    public override bool IsGrouped { get { return false; } }

    public override bool IsAggregate { get { return false; } }
}
我不确定HQL或LINQ,因为我很少使用它们,尤其是LINQ,我从一开始就没有使用过,并认为它是一种有毒资产,并且明确地阻止我的队友使用它

当然,这种方法需要更新现有的查询,但我认为应用它并不十分耗时,因为这是对标准NHibernate排序的替代,所以通过搜索和替换,您可以替换所有出现的排序。您可以安排一个复杂的排序规则投影,只需检查提供的条件和属性名称,即可知道何时应用排序规则

对于实现自定义投影,阅读NHibernate源代码是获得知识的好方法,因为几乎没有涉及此主题的文档


我认为拦截IInterceptor.OnPrepareStatement不是一个好的选择,但是如果您想继续这个方向,那么您可以尝试从原始SQL字符串的部分重新生成SQL字符串,嗅探过程中的ORDER BY子句。我想从来没有人这样做过,所以你要做很多实验,会有很多奇怪的查询让你大吃一惊。

排序规则不仅涉及order by,事实上还涉及任何字符串比较(相等,比如,…)。解析查询(虽然可能是())看起来像是一项庞大的工作,有很多执行开销。也许为您的数据库考虑不同的排序是最简单的解决方案。@jbl-我知道排序不仅仅是排序,但是,出于应用程序的目的,我们只需要关注排序。由于我在现有文章中提到的原因,在数据库级别使用不同的排序规则设置是不可行的。当你写“由于NHibernate在整个代码库中的使用方式不同…”时,你的意思是有HQL、ICriteria、纯SQL、QueryOver和Linq吗?(我在我的代码库中有所有这些)我必须承认,除了解析查询,或者派生您自己的NH分支来覆盖所有需要排序的位置之外,我没有其他选择involved@jbl是的,就是这样。我们在代码库中结合了所有这些方法。我认为解析生成的SQL查询可能是唯一的选择,但是,是否可以用面向对象的方式而不仅仅是字符串操作来实现这一点?(也就是说,是否有可能从原始Sql字符串以编程方式对NHibernate“表达式树”之类的东西进行反向工程?)
session.QueryOver<Item>()
    .OrderBy(new OrderByWithCollate("Name", "Latin1_General_CI_AS")).Asc
    .List();
SELECT * FROM Item ORDER BY Name COLLATE Latin1_General_CI_AS asc