首先,我是NHibernate的新手。我在许多页面中搜索了QueryOver的内容,但对我来说最有利可图的页面是http://nhibernate.info/blog/2009/12/17/queryover-in-nh-3-0.html。多亏了它,我已经到了一个半解决方案"我想,但我需要这个解决方案更好。
我有这些课程:
public class Variable
{
public virtual int Id {get; set; }
public virtual string Nombre { get; set; }
public virtual string Descripcion { get; set; }
public virtual IList<ValorVariable> Valores { get; set; }
public virtual bool Temporal { get; set; }
public virtual bool Eliminado{ get; set; }
}
public class ValorVariable
{
public virtual int Id {get; set; }
public virtual int IdVariable { get; set; }
public virtual Variable Variable { get; set; }
public virtual DateTime FechaValor { get; set; }
public virtual decimal Valor { get; set; }
}
public class VariableLigera
{
public virtual int Id {get; set; }
public string Nombre { get; set; }
public string Descripcion { get; set; }
public bool Temporal { get; set; }
public Decimal Valor { get; set; }
}
变量是&#34;重要的&#34; class,除其他外,有一个IList of&#34; ValorVariable&#34; s,它有一个值(&#34; Valor&#34;)和一个值日期(&#34; FechaValor&#34;) 。 &#34; VariableLigera&#34;就像一个&#34;光&#34;变量类,具有Variable的一些属性和ValorVariable List的一个值。我希望这很清楚。
要填充VariableLigera,我尝试进行QueryOver。我想做这样的事情:
Variable variableAlias = null;
VariableLigera variableLigeraAlias = null;
var result = _session
.QueryOver(() => variableAlias ).Where(x => x.Eliminado == false)
.Select(
Projections.Property(() => variableAlias .Id).WithAlias(() => variableLigeraAlias .Id),
Projections.Property(() => variableAlias .Nombre).WithAlias(() => variableLigeraAlias .Nombre),
Projections.Property(() => variableAlias .Descripcion).WithAlias(() => variableLigeraAlias .Descripcion),
Projections.Property(() => variableAlias .Temporal).WithAlias(() => variableLigeraAlias .Temporal),
Projections.Property(() => variableAlias .Valores.FirstOrDefault().Valor).WithAlias(() => variableLigeraAlias .Valor)
)
.TransformUsing(Transformers.AliasToBean<VariableLigera>())
.List<VariableLigera>();
这就是问题所在。我想加入物业&#34; Valor&#34;变量LigeraAlias是VariableLigera的Valores列表的FirstOrDefault值。但是它抛出了一个例外,&#34;函数FirstOrDefault无法识别&#34;。
所以我尝试了另一件事,为ValorVariable创建一个别名并将其加入查询。像这样:
Variable variableAlias = null;
VariableLigera variableLigeraAlias = null;
ValorVariable valorVariableAlias = null;
var result = _session
.QueryOver(() => variableAlias).Where(x => x.Eliminado == false)
.JoinAlias(() => variableAlias.Valores, () => valorVariableAlias)
.Select(
Projections.Property(() => variableAlias.Id).WithAlias(() => variableLigeraAlias.Id),
Projections.Property(() => variableAlias.Nombre).WithAlias(() => variableLigeraAlias.Nombre),
Projections.Property(() => variableAlias.Descripcion).WithAlias(() => variableLigeraAlias.Descripcion),
Projections.Property(() => variableAlias.Temporal).WithAlias(() => variableLigeraAlias.Temporal),
Projections.Property(() => valorVariableAlias.Valor).WithAlias(() => variableLigeraAlias.Valor)
)
.TransformUsing(Transformers.AliasToBean<VariableLigera>())
.List<VariableLigera>();
使用此查询,我得到结果,但我得到每个变量多次(ValoresVariables列表中每个值一个重复)。例如,如果一个变量有3个值,则查询将返回3&#34; VariablesLigera&#34; s,其中包含3个值,但我只想要一个具有它的第一个值的列表。
简而言之,为了清楚起见,我希望每个变量都有一个结果,其值为(&#34; Valor&#34;)列表中的firstordefault值。是否可以使用QueryOver?非常感谢。
PS:由于英语不是我的母语,也许有些事情不太容易理解。如果有任何疑问,请随时询问。再次感谢。答案 0 :(得分:5)
一般来说,QueryOver查询要记住的事情是它们最终会变成SQL。考虑到这一点,无论何时访问嵌套属性,都需要考虑连接或子查询来完成工作。
在这种情况下,您需要使用子查询来获取第一个ValorVariable.Valor
:
Variable variableAlias = null;
VariableLigera variableLigeraAlias = null;
var result = _session
.QueryOver(() => variableAlias).Where(x => x.Eliminado == false)
.Select(
Projections.Property(() => variableAlias.Id).WithAlias(() => variableLigeraAlias.Id),
Projections.Property(() => variableAlias.Nombre).WithAlias(() => variableLigeraAlias.Nombre),
Projections.Property(() => variableAlias.Descripcion).WithAlias(() => variableLigeraAlias.Descripcion),
Projections.Property(() => variableAlias.Temporal).WithAlias(() => variableLigeraAlias.Temporal),
Projections.Subquery(
QueryOver.Of<ValorVariable>()
.Where(vv => vv.Variable.Id == variableAlias.Id)
.Select(vv => vv.Valor)
.Take(1)
).WithAlias(() => variableLigeraAlias.Valor)
)
.TransformUsing(Transformers.AliasToBean<VariableLigera>())
.List<VariableLigera>();
这将生成如下所示的SQL:
SELECT
/*Variable properties */
(
SELECT
TOP(1) this_0_.Valor AS y0_
FROM
ValorVariable this_0_
WHERE
this_0_.VariableID = this_.ID
) AS y1_
FROM
Variable this_
WHERE
this_.Eliminado = 0
现在,正如@Carl指出的那样,你可能应该通过某种方式来命令你的子查询结果,以便采用&#34;第一条记录&#34;实际上意味着什么。
为此,您可以在子查询中添加OrderBy
:
QueryOver.Of<ValorVariable>()
.Where(vv => vv.Variable.Id == variableAlias.Id)
.Select(vv => vv.Valor)
.OrderBy(vv => vv.FechaValor).Desc
.Take(1)
除了ORDER BY
子句之外,哪个会产生类似的SQL。
此外,由于您使用FirstOrDefault
,这意味着Valor
属性可能是null
。如果是这种情况,您应该将VariableLigera.Valor
属性更改为decimal?
(可为空decimal
)。
答案 1 :(得分:2)
如果我了解您,VariableLigera
正在作为实体Variable
的DTO运行。您需要Variable
的大部分属性和Valores
集合的一个值。
除非您想要集合的任何值,否则您需要指定选择第一个值的条件。由于VariableValor
具有日期属性,因此我们使用它来选择最新值。
这是用子查询来做这件事。
未经测试的代码(它编译,但我没有执行它:
Variable variableAlias = null;
VariableLigera variableLigeraAlias = null;
ValorVariable valorVariableAlias = null;
var result = _session
.QueryOver(() => variableAlias).Where(x => x.Eliminado == false)
.JoinAlias(() => variableAlias.Valores, () => valorVariableAlias)
.SelectList(projections => projections
.Select(() => variableAlias.Id).WithAlias(() => variableLigeraAlias.Id),
.Select(() => variableAlias.Nombre).WithAlias(() => variableLigeraAlias.Nombre),
.Select(() => variableAlias.Descripcion).WithAlias(() => variableLigeraAlias.Descripcion),
.Select(() => variableAlias.Temporal).WithAlias(() => variableLigeraAlias.Temporal),
.SelectSubQuery(QueryOver.Of<ValorVariable>( () => valorVariableAlias)
.Where(vv => vv.IdVariable == variableAlias.Id)
.Select(Projections.Max<ValorVariable>(vv => vv.FechaValor)))
.Select(Projections.Property(() => valorVariableAlias.Valor))
.WithAlias(() => variableLigeraAlias.Valor)
)
.TransformUsing(Transformers.AliasToBean<VariableLigera>())
.List<VariableLigera>();