我认为这样做应该可以解决问题:
session.QueryOver<MyTable>()
.Select(
Projections.Group<MyTable>(x => x.Id),
Projections.Sum(
Projections.Conditional(
Restrictions.Eq(
Projections.Property<MyTable>(x => x.MyValue), 1),
Projections.Property<MyTable>(x => x.Volume),
Projections.SqlFunction(
new VarArgsSQLFunction("(", "*", ")"),
NHibernateUtil.Int32,
Projections.Property<MyTable>(x => x.Volume),
Projections.Constant(-1)))))
.List<object[]>();
作为一条规则,QueryOver在进行算术运算时表现得相当糟糕。据我所知,您必须使用
VarArgsSQLFunction
来构建乘法表达式。
这会生成以下SQL语句:
SELECT
this_.Id as y0_,
sum((
case when this_.MyValue = 1
then this_.Volume else (this_.Volume*-1) end
)) as y1_
FROM
MyTable this_
GROUP BY
this_.Id
请注意,在此处您需要使用与自定义DTO配对的结果转换器,或者使用
.List<object[]>
,它将结果集转换为
List
of
object[]
,每个
List
中的项目都是一个结果行。你不能仅使用
.List()
,因为NHibernate期望选择整个
MyTable
行,而在这里你并没有这样做。
您可能认为这很丑陋,我也同意。您可以通过将投影重构为它们自己的变量来进行一些清理:
IProjection multiplicationProjection =
Projections.SqlFunction(
new VarArgsSQLFunction("(", "*", ")"),
NHibernateUtil.Int32,
Projections.Property<MyTable>(t => t.Volume),
Projections.Constant(-1));
IProjection conditionalProjection =
Projections.Conditional(
Restrictions.Eq(
Projections.Property<MyTable>(t => t.MyValue), 1),
Projections.Property<MyTable>(t => t.Volume),
multiplicationProjection);
session.QueryOver<MyTable>()
.SelectList(list => list
.SelectGroup(t => t.Id)
.Select(Projections.Sum(conditionalProjection)))
.List<object[]>();
NHibernateUtil.Decimal
,我就不会出错。在C#类中,Volume
的类型是什么? - Andrew Whitaker