Linq to NHibernate: сумма сумм

Наличие объектов NHibernate:

Company, Invoice и InvoiceLine с десятичным свойством Price.

Company имеет коллекцию типа Invoice, а Invoice имеет коллекцию типа InvoiceLine.

Как я могу получить сумму всех цен, принадлежащих строкам счета-фактуры, которые относятся к счетам-фактурам определенной компании, указанной идентификатором?

Пробовал написать запрос так:

session
    .Query<InvoiceLine>()
    .Where(invoiceLine => invoiceLine.Invoice.Company.Id == companyId)
    .Sum(invoiceLine => invoiceLine.Price);

но выдает исключение:

NHibernate.Exceptions.GenericADOException
"Could not execute query[SQL: SQL not available]"

   at NHibernate.Impl.SessionImpl.List(IQueryExpression queryExpression, QueryParameters queryParameters, IList results)
   at NHibernate.Impl.AbstractSessionImpl.List(IQueryExpression queryExpression, QueryParameters parameters)
   at NHibernate.Impl.ExpressionQueryImpl.List()
   at NHibernate.Linq.DefaultQueryProvider.ExecuteQuery(NhLinqExpression nhLinqExpression, IQuery query, NhLinqExpression nhQuery)
   at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
   at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression)
   at System.Linq.Queryable.Sum[TSource](IQueryable`1 source, Expression`1 selector)

внутреннее исключение:

System.ArgumentNullException
"Value cannot be null.\r\nParameter name: item"

   at System.ThrowHelper.IfNullAndNullsAreIllegalThenThrow[T](Object value, ExceptionArgument argName)
   at System.Collections.Generic.List`1.System.Collections.IList.Add(Object item)
   at NHibernate.Util.ArrayHelper.<>c__DisplayClass2.<AddAll>b__0()
   at NHibernate.Util.ArrayHelper.AddAll(IList to, IList from)
   at NHibernate.Engine.Query.HQLQueryPlan.PerformList(QueryParameters queryParameters, ISessionImplementor session, IList results)
   at NHibernate.Impl.SessionImpl.List(IQueryExpression queryExpression, QueryParameters queryParameters, IList results)

Это может иметь какое-то отношение к суммированию пустых коллекций, но я не уверен, как это исправить.


person Răzvan Flavius Panda    schedule 08.08.2013    source источник


Ответы (3)


Попробуйте преобразовать Price в nullable decimal...

.Sum(invoiceLine => (decimal?)invoiceLine.Price) ?? 0;

Результат явно decimal?

person xanatos    schedule 08.08.2013
comment
Это почти решение, пожалуйста, измените его на .Sum(invoiceLine => (decimal?)invoiceLine.Price) ?? 0, чтобы я мог проголосовать и принять. - person Răzvan Flavius Panda; 24.09.2013

Решение, помеченное как ответ, не спасло меня от проблемы. Вместо GenericAdoException я получил InvalidOperationException со следующим стеком.

Предлагаемое здесь решение Linq: выберите коллекцию свойств является фактическим решением для меня.

Une erreur inattendue de type InvalidOperationException s'est produite sur le serveur
System.InvalidOperationException: Code supposed to be unreachable
   à System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
   à System.Linq.Expressions.Compiler.StackSpiller.RewriteUnaryExpression(Expression expr, Stack stack)
   à System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
   à System.Linq.Expressions.Compiler.StackSpiller.RewriteExpressionFreeTemps(Expression expression, Stack stack)
   à System.Linq.Expressions.Compiler.StackSpiller.Rewrite[T](Expression`1 lambda)
   à System.Linq.Expressions.Expression`1.Accept(StackSpiller spiller)
   à System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda, DebugInfoGenerator debugInfoGenerator)
   à System.Linq.Expressions.Expression`1.Compile()
   à NHibernate.Linq.ExpressionToHqlTranslationResults.MergeLambdasAndCompile[TDelegate](IList`1 itemTransformers)
   à NHibernate.Linq.ExpressionToHqlTranslationResults..ctor(HqlTreeNode statement, IList`1 itemTransformers, IList`1 listTransformers, IList`1 postExecuteTransformers, List`1 additionalCriteria)
   à NHibernate.Linq.IntermediateHqlTree.GetTranslation()
   à NHibernate.Linq.Visitors.QueryModelVisitor.GenerateHqlQuery(QueryModel queryModel, VisitorParameters parameters, Boolean root)
   à NHibernate.Linq.NhLinqExpression.Translate(ISessionFactoryImplementor sessionFactory, Boolean filter)
   à NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)
   à NHibernate.Engine.Query.QueryExpressionPlan.CreateTranslators(IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
   à NHibernate.Engine.Query.QueryExpressionPlan..ctor(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
   à NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters)
   à NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow)
   à NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression)
   à NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, IQuery& query, NhLinqExpression& nhQuery)
   à NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
   à NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression)
   à System.Linq.Queryable.Sum[TSource](IQueryable`1 source, Expression`1 selector)
   à Secib.Server.Services.ReglementService.GetRegleTtc(FactureView facture) dans x:\Sources\Next\Alpha\SecibNext\Secib.Server\Services\ReglementService.cs:ligne 425
   à Secib.Server.Services.ReglementService.DoesMontantSoldeFacture(FactureView facture, Decimal montantImpute) dans x:\Sources\Next\Alpha\SecibNext\Secib.Server\Services\ReglementService.cs:ligne 391
   à Secib.Server.Services.ReglementService.DispatcheMontantImpute(Reglement reglement, ReglementFactureCompactDto factureDto) dans x:\Sources\Next\Alpha\SecibNext\Secib.Server\Services\ReglementService.cs:ligne 236
   à Secib.Server.Services.ReglementService.SaveReglement(Reglement reglement, IList`1 factures) dans x:\Sources\Next\Alpha\SecibNext\Secib.Server\Services\ReglementService.cs:ligne 197
   à Secib.Server.Controllers.ReglementController.<SaveReglement>z__OriginalMethod() dans x:\Sources\Next\Alpha\SecibNext\Secib.Server\Controllers\ReglementController.cs:ligne 141
   à Secib.Server.Controllers.ReglementController.<SaveReglement>c__Binding.Invoke(Object& instance, Arguments arguments, Object aspectArgs) dans :ligne 0
   à PostSharp.Aspects.Internals.MethodInterceptionArgsImpl`1.Proceed()
   à Secib.Server.Aspects.TransactionAspect.OnInvoke(MethodInterceptionArgs args) dans x:\Sources\Next\Alpha\SecibNext\Secib.Server\Aspects\TransactionAspect.cs:ligne 32
person bN_    schedule 12.06.2015
comment
Какое внутреннее исключение вы получаете и как выглядят ваши запросы/сущности? Если что-то не изменилось в том, как это работает, я уверен, что принятый ответ работает. - person Răzvan Flavius Panda; 12.06.2015
comment
Этот SelectMany второй фрагмент кода также делает 2 запроса к БД вместо 1 (можно было бы написать с использованием фьючерсов, но это все равно было бы менее эффективно). - person Răzvan Flavius Panda; 12.06.2015
comment
Внутреннее исключение равно нулю. Запрос очень простой и очень похож на ваш: return Session.Query‹ReglementFacture›() .Where(x =› x.Facture == facture) .Sum(x =› (decimal?)x.MontantRegle ?? 0) ; Где на Facture ссылается ReglementFacture (многие к одному), а MontantRegle является десятичным (и столбец не может принимать значения NULL). НХ v 4.0.0.4000 - person bN_; 15.06.2015
comment
Вам нужно вызвать ?? для всего запроса, а не внутри лямбда-суммы: return Session.Query<ReglementFacture>() .Where(x => x.Facture == facture) .Sum(x => (decimal?)x.MontantRegle) ?? 0; Это потому, что Sum вернет null, когда в коллекции нет элементов. И вам нужно привести к decimal?, потому что Sum может возвращать значение null для пустой коллекции, а тип возвращаемого значения выводится из того, какой тип вы возвращаете. - person Răzvan Flavius Panda; 15.06.2015

person    schedule
comment
Он выдает исключение не потому, что есть нулевые цены, а потому, что база данных возвращает ноль при суммировании пустой коллекции. Так что это не решит проблему ОП. - person Ε Г И І И О; 13.07.2018