NHibernate QueryOver CASE WHEN 计算列值
NHibernate QueryOver CASE WHEN calculate on column value
我一直在尝试在 NHibernate QueryOver 中执行以下 T-SQL,但没有成功:
SELECT Id, SUM(CASE MyValue WHEN 1 THEN Volume ELSE Volume * -1 END)
FROM MyTable
GROUP BY Id
我正在尝试总结所有体积,但 MyValue=1
应该是正值,否则是负值。到目前为止我得到了:
var result = this.Session.QueryOver<MyTable>()
.Select(Projections.Group<MyTable>(x => x.Id),
Projections.Conditional(Restrictions.Eq(Projections.Property<MyTable>(x
=> x.MyValue), '1'),
Projections.Property<MyTable>(x => x.Volume),
Projections.Property<MyTable>(x => x.Volume * -1)))
.List();
但是你可以想象 NHibernate 不知道列 Volume * -1
,那么我如何在我的 CASE 中进行这个计算?
我认为这应该可以解决问题:
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
的 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[]>();
我一直在尝试在 NHibernate QueryOver 中执行以下 T-SQL,但没有成功:
SELECT Id, SUM(CASE MyValue WHEN 1 THEN Volume ELSE Volume * -1 END)
FROM MyTable
GROUP BY Id
我正在尝试总结所有体积,但 MyValue=1
应该是正值,否则是负值。到目前为止我得到了:
var result = this.Session.QueryOver<MyTable>()
.Select(Projections.Group<MyTable>(x => x.Id),
Projections.Conditional(Restrictions.Eq(Projections.Property<MyTable>(x
=> x.MyValue), '1'),
Projections.Property<MyTable>(x => x.Volume),
Projections.Property<MyTable>(x => x.Volume * -1)))
.List();
但是你可以想象 NHibernate 不知道列 Volume * -1
,那么我如何在我的 CASE 中进行这个计算?
我认为这应该可以解决问题:
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
的 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[]>();