2013-09-09 5 views
4

У меня есть большое приложение ASP.NET, которое использует NHibernate (v3.2.0.4000) для доступа к SQL Server 2005 в качестве внутреннего хранилища данных. У нас есть несколько клиентов, каждый клиент имеет собственную базу данных, но все базы данных работают на одном сервере.Изменить сортировку по запросам NHibernate

Быстрый вопрос:
Без установки COLLATION на сервере базы данных, или сами, или переписывание существующего индивидуального NHibernate код запроса отдельных базы данных, как я могу добавить пользовательские операторы COLLATION на запросы NHibernate, чисто для заказа целей , прежде чем они попадут в базу данных?

Вопрос дольше:
Из-за наличия новых международных клиентов нам необходимо поддерживать пользовательскую сортировку для сортировки в нашем приложении. Мы не можем сделать это на уровне базы данных (или сервера), поскольку мы размещаем отдельную базу данных для каждого клиента на том же сервере (каждый клиент может иметь разные требования к сопоставлению), и есть сложности с такими вещами, как TempDB и т. Д., И несколько разных сопоставления на том же сервере (см. here и here).

В результате различия в том, как NHibernate используется на всей кодовой базе (например, комбинация HQL, ICriteria, простой SQL, QueryOver и Linq), и поскольку многие из этих запросов очень сложны и беспорядочны, мы хотим полностью избегайте изменения любого существующего кода запроса NHibernate.

SQL Server позволит ссылаться запросом с определенной комплектовкой применяется на время выполнения этого запроса, например, так: SELECT * FROM Customer ORDER BY Surname COLLATE Latin1_General_CI_AS

Я также знаю, что NHibernate позволяет создание Interceptor, которые могут быть добавлены в NHibernate на основе глобального или сеанса (как показано here), что позволяет перехватить инструкцию SQL до ее отправки на SQL Server.

Кажется, я могу написать класс перехватчика, чтобы перехватить SQL-заявление, но это просто позволяет мне захватить необработанное SQL-заявление (в комплекте с странными и прекрасными именами и псевдонимами NHibernate). Я не знаю, есть ли способ, чтобы я мог чисто проанализировать определенные части запроса (мне нужно только предложение ORDER BY) и изменить отдельные составляющие части предложения ORDER BY (т.е. отдельные поля) после проверки того, что поля основаны на тексте и позволят добавить к ним инструкцию COLLATE.

NHibernate предоставляет интерфейс NHibernate.SqlCommand.ISqlStringVisitor, который звучит многообещающе и, кажется, работают на SqlString захваченной в OnPrepareStatement способе EmptyInterceptor класса, который может быть переопределен, однако, я совершенно не знаком с этой частью NHibernate, и это Безразлично» t помочь, что в настоящее время, как я пишу это, NHibernate, предположительно, окончательный источник информации, nhibernate.info, не работает (и, похоже, уже несколько недель)!

Должен ли кто-нибудь выполнять такую ​​задачу? Возможно ли исключить запросы NHibernate чистым и безопасным способом? Существует ли совершенно другой подход, который мог бы достичь того же самого (учитывая те же ограничения, что и неспособность изменить сортировку базы данных/сервера)?

+0

Учет не только в порядке, но и в любом сравнении строк (равенство, например, ...). Разбор запроса, хотя это возможно (http://codetype.wordpress.com/2012/11/01/net-sql-parsing-using-the-tsqlparser-library/), кажется огромной работой, с большим количеством выполнение служебных обязанностей. Возможно, это простое решение для разных баз данных. – jbl

+0

@jbl - Я понимаю, что для сопоставления больше, чем для заказа, но для целей нашего приложения нам нужно только заботиться о заказе. Использование разных настроек сортировки на уровне базы данных нецелесообразно по причинам, указанным в моем существующем сообщении. – CraigTP

+0

Когда вы пишете «В результате различия в том, как NHibernate используется во всей кодовой базе ...», вы имеете в виду, что существуют HQL, ICriteria, простой SQL, QueryOver и Linq? (У меня есть все это в моей кодовой базе). Должен признаться, я не вижу другого выбора, кроме синтаксического анализа запроса, или получаю собственную ветвь NH для переопределения всех мест, где задействовано упорядочение. – jbl

ответ

4

Вы можете сделать это относительно легко, используя пользовательскую проекцию.Следующий класс является хорошей отправной точкой:

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; } } 
} 

Однако этот подход, очевидно, применимо только к CriteriaAPI и QueryOver:

session.QueryOver<Item>() 
    .OrderBy(new OrderByWithCollate("Name", "Latin1_General_CI_AS")).Asc 
    .List(); 

SQL, из этого запроса аналогична:

SELECT * FROM Item ORDER BY Name COLLATE Latin1_General_CI_AS asc 

Я не уверен в HQL или LINQ, поскольку я редко их использую, особенно LINQ, который я никогда не использовал и не рассматривал его с самого первого дня как токсичный актив, и явно не поощрял моих товарищей по команде использовать Это.

Конечно, этот подход требует обновления существующих запросов, но я считаю, что это не очень трудоемко, потому что это замена замены стандартного заказа NHibernate, поэтому путем поиска и замены вы можете заменить все вхождения порядка. Вы можете организовать сложный метод CollationProjection, который знает, когда применять сопоставление, просто проверяя предоставленные критерии и имя свойства.

Для реализации пользовательских прогнозов чтение исходного кода NHibernate является хорошим способом получения знаний, так как почти нет документа, охватывающего эту тему.

Я не думаю, что перехват IInterceptor.OnPrepareStatement - хороший вариант, но если вы хотите продолжить в этом направлении, то вы можете попробовать перестроить строку SQL из частей исходной строки SQL, обнюхивая для предложения ORDER BY в процессе. Я предполагаю, что никто никогда не делал этого, поэтому у вас много экспериментов, будет много нечетных запросов, которые укусят вас врасплох.

+0

Я желаю избежать изменения (или перезаписи) существующих запросов NHibernate, поскольку это не только трудоемкая работа, но и потенциал для ввода тонких ошибок в запросах. Наши запросы NHibernate обширны и (как упоминалось в другом комментарии) представляют собой комбинацию HQL, ICriteria, простого SQL, QueryOver и Linq, поэтому применение таких вещей, как «Прогнозы», может быть проблематичным. Похоже, что «IInterceptor.OnPrepareStatement» - это возможный способ избежать касания существующих запросов, но это, конечно же, связано с его собственными значительными осложнениями. – CraigTP

+0

Для поддержки HQL этот [вопрос] (/ q/4201583/1178314) имеет решение.После поддержки HQL поддержка в Criteria или QueryOver должна быть прямой, в то время как поддержка Linq может быть выполнена с большей работой [здесь] (/ q/35488353/1178314). Но все это потребует изменения кода и для всех запросов. Решение «IInterceptor» выглядит для меня единственным, позволяющим не касаться кода запросов, но, как вы сами заявляете, это было бы довольно сложно. –