2016-02-18 3 views
3

Можно заказать по типу класса в запросах HQL и ICriteria, используя специальный класс ключевых слов.Можно заказать по типу класса в NHibnernate IQueryable

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

Можно ли использовать это ключевое слово в IQueryable OrderBy? Это похоже только на неправильные выражения, а .GetType() не поддерживается.

+0

Похоже, что специальное свойство HQL 'class' для базовых объектов устарело на стороне Hibernate, в пользу функции HQL' type (entityAlias) '. См. Это [doc info notice] (http://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/Hibernate_User_Guide.html#hql-entity-type-exp). Но я не нашел никакой информации о том, что такое позиция NHibernate по этому вопросу. –

ответ

4

Быстрого & Грязного предложение

Грязный хак может работать. По моему опыту, linq2NH переводит запросы на HQL без особых проверок (см. this question для примерного примера в его примере кода «trick»). Таким образом, вы можете добавить фиктивный и не отображаемый объект public virtual string @class { get; set; } на свой базовый объект, а затем заказать его.

session.Query<YourBaseEntityType>().OrderBy(e => [email protected]); 

Test это, вероятно, было бы перевести «прямо» на рабочий HQL запроса. Конечно, это некрасиво, может сломаться в любой NH обновления версии, ...

(The @ требуется потому, что class является зарезервированным словом в C#. Приставка с @ сообщает компилятору, что это просто имя, а не class ключевое слово.)

уборщик предложение

уборщик способом было бы extend linq2NH для поддержки метода Class() на ваших лиц. (Сообщение в блоге найдено на this answer to another question Edit:.. Вот еще один интересный 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():base() 
    { 
     RegisterGenerator(
      NHibernate.Linq.ReflectionHelper.GetMethod(
       () => YourLinqExtensions.Class(null)), 
      new ClassGenerator()); 
    } 
} 

и настроить NH использовать новый реестр. С hibernate.cfg.xml, это должно быть что-то, как добавить следующий property узел под session-factory узла:

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

Использование:

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

(С тем, как я разработал все это, он должен в наименее компилируемый, но он полностью непроверен. Edit: теперь он протестирован.)

+0

Было бы неплохо быть уверенным, что оно протестировано и работает. Но в качестве концепции вы отлично поработали здесь ... –

+0

Грязное предложение работает. Мне не удалось заставить работать более чистое предложение. Он генерирует NHibernate.Hql.Ast.ANTLR.QuerySyntaxException «Произошла ошибка распознавания». Я использую NHibernate 4.0.0.4000 – Skippy

+0

@ RadimKöhler, да, я согласен, ответы должны быть проверены. Но у меня нет dev env дома (даже MS Windows действительно), и делать это с работы - это не то, за что мне платят. Таким образом, по оставшимся без ответа вопросам, помощь в некоторых непроверенных предложениях может помочь. –

1

В зависимости от ваших потребностей должно работать выражение сортировки, основанное на сравнении определенного типа. Например (простите VB.NET):

Dim o = Session.Query(Of Animal).OrderBy(Function(x) If(TypeOf x Is Cat, 1, 2)).ToList() 
+0

Пока я был на этом предмете, я скептически протестировал C# перевод вашего предложения. Но это действительно работает. 'session.Query (). OrderBy (e => e - SomeChildClass? 1: 2);' –

Смежные вопросы