NHibernate与linq保持联系

时间:2017-02-23 08:48:06

标签: c# mysql linq join nhibernate

我需要更改使用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中进行左连接。 任何帮助表示赞赏

1 个答案:

答案 0 :(得分:1)

目前不支持任意左连接(v4.1)。它们转换为LINQ GroupJoin,与一起使用时会抛出NotImplementedException

answer所链接的David中所述,您可以使用代替。普通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}}。