2014-02-05 2 views
3

Возможно, что-то не так с моим запросом Linq, или я сталкиваюсь с тем, что NHibernate не поддерживает. В любом случае, это странно. Вот мой запрос, делает работу:Добавление нескольких предложений ORDER BY в запрос NHibernate вызывает исключение

// Query for all ingredients, most used ingredients first 
var ingredients = (from ing in session.Query<Ingredients>() 
        orderby ((from p in session.Query<RecipeIngredients>() 
          where p.Ingredient == ing 
          select p.RecipeIngredientId).Count()) descending 
        select new IngredientSource(ing.IngredientId, ing.DisplayName)); 

Это производит запрос:

select 
    ingredient0_.IngredientId as col_0_0_, 
    ingredient0_.DisplayName as col_1_0_ 
from ingredients ingredient0_ 
order by (select cast(count(recipeingr1_.RecipeIngredientId) as int4) from recipeingredients recipeingr1_ where recipeingr1_.IngredientId=ingredient0_.IngredientId) desc 

Я не очень нравится странно cast() вещь происходит, но я сомневаюсь, что тормозит что-нибудь вниз.

Однако, мне нужно добавить второй заказ. Результаты должны быть отсортированы по имени ингредиента далее. Так что я попытался очевидное:

var ingredients = (from ing in session.Query<Ingredients>() 
        orderby ((from p in session.Query<RecipeIngredients>() 
          where p.Ingredient == ing 
          select p.RecipeIngredientId).Count()) descending, 
          ing.DisplayName 
        select new IngredientSource(ing.IngredientId, ing.DisplayName)); 

Это бросает исключение:

NHibernate.Hql.Ast.ANTLR.QuerySyntaxException was unhandled 
    HResult=-2146232832 
    Message=Exception of type 'Antlr.Runtime.MismatchedTreeNodeException' was thrown. [.Select[KitchenPC.DB.Models.Ingredients,KitchenPC.Context.IngredientSource](.ThenBy[KitchenPC.DB.Models.Ingredients,System.String](.OrderByDescending[KitchenPC.DB.Models.Ingredients,System.Int32](NHibernate.Linq.NhQueryable`1[KitchenPC.DB.Models.Ingredients], Quote((ing,) => (.Count[System.Guid](.Select[KitchenPC.DB.Models.RecipeIngredients,System.Guid](.Where[KitchenPC.DB.Models.RecipeIngredients](NHibernate.Linq.NhQueryable`1[KitchenPC.DB.Models.RecipeIngredients], Quote((p,) => (Equal(p.Ingredient, ing))),), Quote((p,) => (p.RecipeIngredientId)),),))),), Quote((ing,) => (ing.DisplayName)),), Quote((ing,) => (new IngredientSource(ing.IngredientId, ing.DisplayName,))),)] 
    Source=NHibernate 
    QueryString=.Select[KitchenPC.DB.Models.Ingredients,KitchenPC.Context.IngredientSource](.ThenBy[KitchenPC.DB.Models.Ingredients,System.String](.OrderByDescending[KitchenPC.DB.Models.Ingredients,System.Int32](NHibernate.Linq.NhQueryable`1[KitchenPC.DB.Models.Ingredients], Quote((ing,) => (.Count[System.Guid](.Select[KitchenPC.DB.Models.RecipeIngredients,System.Guid](.Where[KitchenPC.DB.Models.RecipeIngredients](NHibernate.Linq.NhQueryable`1[KitchenPC.DB.Models.RecipeIngredients], Quote((p,) => (Equal(p.Ingredient, ing))),), Quote((p,) => (p.RecipeIngredientId)),),))),), Quote((ing,) => (ing.DisplayName)),), Quote((ing,) => (new IngredientSource(ing.IngredientId, ing.DisplayName,))),) 
    StackTrace: 
     at NHibernate.Hql.Ast.ANTLR.ErrorCounter.ThrowQueryException() 
     at NHibernate.Hql.Ast.ANTLR.HqlSqlTranslator.Translate() 
     at NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.Analyze(String collectionRole) 
     at NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.DoCompile(IDictionary`2 replacements, Boolean shallow, String collectionRole) 
     at NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.Compile(IDictionary`2 replacements, Boolean shallow) 
     at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(IASTNode ast, String queryIdentifier, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory) 
     at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(String queryIdentifier, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory) 
     at NHibernate.Engine.Query.HQLExpressionQueryPlan.CreateTranslators(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory) 
     at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory) 
     at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String expressionStr, IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory) 
     at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters) 
     at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow) 
     at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression) 
     at NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, IQuery& query, NhLinqExpression& nhQuery) 
     at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression) 
     at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression) 
     at Remotion.Linq.QueryableBase`1.GetEnumerator() 
     at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) 
     at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) 
     at KitchenPC.DB.DatabaseAdapter.LoadIngredientsForIndex() in c:\KitchenPC\DB\DatabaseAdapter.cs:line 172 

Что я делаю неправильно?

+0

Для меня это выглядит как внутренняя ошибка NHibernate. – dasblinkenlight

+0

@dasblinkenlight - Согласен. Я рад зарегистрировать ошибку, но я надеюсь, что есть работа, чтобы разблокировать меня сейчас. –

+0

@MikeChristensen: Использует ли другая технология запросов, например QueryOver? –

ответ

0

Я перевел запрос Linq на запрос ICriteria (QueryOver<>), и это, похоже, сработает. Однако код довольно грязный. Или, удивительно, в зависимости от того, в чем вы находитесь.

Models.Ingredients ing = null; 
int? count = null; 
var popularity = QueryOver.Of<Models.RecipeIngredients>() 
    .Where(p => p.Ingredient.IngredientId == ing.IngredientId) 
    .ToRowCountQuery(); 

var ingredients = session.QueryOver<Models.Ingredients>(() => ing) 
    .SelectList(list => list 
     .Select(p => p.IngredientId) 
     .Select(p => p.DisplayName) 
     .SelectSubQuery(popularity).WithAlias(() => count) 
    ) 
    .OrderByAlias(() => count).Desc() 
    .ThenBy(p => p.DisplayName).Asc() 
    .List<Object[]>() 
    .Select(i => new IngredientSource((Guid)i[0], (String)i[1])); 

Это производит очень похожий запрос на оригинал:

SELECT 
    this_.IngredientId as y0_, 
    this_.DisplayName as y1_, 
    (SELECT count(*) as y0_ FROM recipeingredients this_0_ WHERE this_0_.IngredientId = this_.IngredientId) as y2_ 
FROM ingredients this_ 
ORDER BY y2_ desc, this_.DisplayName asc 
+0

По моему опыту провайдер LINQ очень глючит и примерно в 75% случаев даже для умеренно сложных запросов, которые я должен переключить на QueryOver. Я начал писать все в QueryOver сразу с места битвы из-за проблем, подобных этому. –

+0

@AndrewWhitaker - Да, я был наоборот. Я начал писать все с помощью 'QueryOver', но в последнее время начал использовать' Query' больше для очень простых запросов, особенно тех, где вам просто нужна пара столбцов из модели. «QueryOver» определенно более зрелый, так как он построен на «ICriteria» и намного мощнее. Я думаю, что оба имеют свое место, в зависимости от ситуации. Если это ошибка (которая, как представляется,), я бы хотел ее зарегистрировать. –

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