我需要更改使用NHibernate进入左外连接的linq中的连接。 我的代码看起来像这样
IQueryable<DimServicePoint> spq =
from sp in session.Query<DimServicePoint>()
join spm in session.Query<DimServicepointMeter>() on sp.ServicePointKey equals spm.ServicePointKey into gj
from subsp in gj.DefaultIfEmpty()
where (sp.ServicePointID == servicePointID && sp.DimAccount.AccountKey != 0 && sp.StartDayID <= currentDateId && sp.EndDayID >= currentDateId)
select sp;
现在我的要求是在此查询中使用左连接加入DimServicepointMeter。 等效的SQL查询是:
select * from dw.dim_servicepoint sp
left join dw.dim_servicepoint_meter spm on sp.servicepointkey = spm.servicepointkey
where sp.servicepointid = @ServicePointID and sp.accountkey != 0
and sp.startdayid <= @currentDateId and sp.enddayid >= @currentDateId
我在NHibenate或linq上工作不多,所以不知道如何在NHibernate或linq中进行左连接。 任何帮助表示赞赏
答案 0 :(得分:1)
linq-to-nhibernate目前不支持任意左连接(v4.1)。它们转换为LINQ GroupJoin
,与linq-to-nhibernate一起使用时会抛出NotImplementedException
。
如answer所链接的David中所述,您可以使用queryover代替hql。普通here也可以这样做(使用theta样式连接)。
您可以在您的服务点上映射您的仪表。它看起来像(没有你的DimAccount
属性):
public class DimServicePoint
{
public virtual int ServicePointID { get; set; }
public virtual int StartDayID { get; set; }
public virtual int EndDayID { get; set; }
public virtual int ServicePointKey { get; set; }
public virtual ISet<DimServicePointMeter> ServicePointMeters { get; set; }
}
public class DimServicePointMeter
{
public virtual int ServicePointMeterID { get; set; }
public virtual int ServicePointKey { get; set; }
}
映射:
<class name="DimServicePoint">
<id name="ServicePointID">
<generator class="assigned" />
</id>
<property name="StartDayID" />
<property name="EndDayID" />
<property name="ServicePointKey" />
<set name="ServicePointMeters" inverse="true" batch-size="20">
<key column="ServicePointKey" property-ref="ServicePointKey" />
<one-to-many class="DimServicePointMeter" />
</set>
</class>
<class name="DimServicePointMeter">
<id name="ServicePointMeterID">
<generator class="assigned" />
</id>
<property name="ServicePointKey" />
</class>
然后你可以通过以下方式获取数据:
var spq = session.Query<DimServicePoint>()
.Where(sp => sp.ServicePointID == servicePointID && sp.DimAccount.AccountKey != 0 &&
sp.StartDayID <= currentDateId && sp.EndDayID >= currentDateId);
在查询结果上访问.ServicePointMeters
会触发延迟加载的米集合,最多可收集20个加载的服务点。这是由于我提出的映射中的batch-size
属性。如果没有它(并且没有全局配置的batch-size
),它将一次只触发一个集合的延迟加载,可能导致n + 1个性能问题。
如果你想急切加载它们,只需添加fetch:
var spq = session.Query<DimServicePoint>()
.Where(sp => sp.ServicePointID == servicePointID && sp.DimAccount.AccountKey != 0 &&
sp.StartDayID <= currentDateId && sp.EndDayID >= currentDateId)
.FetchMany(sp => sp.ServicePointMeters);
生成的查询将使用左连接。
注:
我个人避免使用类似LINQ sql的语法,我赞成使用LINQ扩展方法,如我的回答所示。我发现它们更具可读性
我倾向于使用NHibernate进行延迟加载,因为它可以批量加载延迟加载。它倾向于简化代码,同时保持良好的性能,正如我已解释{{3}}。