【问题标题】:NHibernate QueryOver with Left Self Join带有左自连接的 NHibernate QueryOver
【发布时间】:2011-09-09 07:11:13
【问题描述】:

我有一个职位表,其中一个职位可以有一个相关的职位(但不一定),每个职位都有一个最后修改日期。然后我想获取在两个给定日期之间修改的所有位置(给定类型)(即“主要”位置或相关位置被修改)。在 SQL 中,我会这样做:

SELECT * FROM ShipPosition sp
LEFT JOIN ShipPosition sp2 ON sp.RelatedShipPositionID = sp2.ShipPositionID
WHERE sp.ShipPositionTypeID IN (11,12)
AND (sp.ModifiedDate BETWEEN '2011-09-09 08:00' AND '2011-09-09 12:00'
     OR sp2.ModifiedDate BETWEEN '2011-09-09 08:00' AND '2011-09-09 12:00')

现在我对 NHibernate (3.0) 和 QueryOver 还很陌生,我在将这个 SQL 查询转换为 C# 代码时遇到了一点问题。我已经阅读了一些 examples 并尝试查看其他问题,但遗憾的是没有运气。

我最初的尝试是这样的:

public IList<ShipPosition> GetModifiedShipPositions(IList<ShipPositionType> positionTypes, DateTime modifiedFrom, DateTime modifiedTo)
{

    var result = Session.QueryOver<ShipPosition>()
        .WhereRestrictionOn(p => p.ShipPositionType).IsInG(positionTypes)
        .And(Restrictions.Or(
            Restrictions.Where<ShipPosition>(p => p.ModifiedDate.IsBetween(modifiedFrom).And(modifiedTo)),
            Restrictions.Where<ShipPosition>(p => p.RelatedShipPosition != null
                                               && p.RelatedShipPosition.ModifiedDate.IsBetween(modifiedFrom).And(modifiedTo))));
    return result.List();
}

但这会引发 KeyNotFoundException(给定的键不在字典中)。我曾尝试使用 JoinQueryOverJoinAlias 进行试验,因为我怀疑这是缺少的其中之一,但我没有设法让它正确。

如果有人能指出我正确的方向(或已经回答的问题),我将不胜感激!

更新:

我尝试使用 linq 编写查询:

var query = Session.Query<ShipPosition>().Where(p
    => positionTypes.Contains(p.ShipPositionType)
    && ((p.ModifiedDate > modifiedFrom && p.ModifiedDate < modifiedTo)
    || (p.RelatedShipPosition != null && p.RelatedShipPosition.ModifiedDate > modifiedFrom && p.RelatedShipPosition.ModifiedDate < modifiedTo)));
return query.ToList();

这并没有引发任何异常,但我没有得到想要的结果(缺少一个案例 p.RelatedShipPosition 为 null。

顺便提一下,使用 HQL 可以正常工作,并给出与 SQL 查询相同的结果:

var queryString = @"
        SELECT shipPosition
        FROM ShipPosition shipPosition
        LEFT JOIN shipPosition.ShipPositionType shipPositionType
        LEFT JOIN shipPosition.RelatedShipPosition relatedShipPosition
        WHERE shipPositionType.SystemName IN (:positionTypes)
        AND (shipPosition.ModifiedDate BETWEEN :modifiedFrom AND :modifiedTo
            OR relatedShipPosition.ModifiedDate BETWEEN :modifiedFrom AND :modifiedTo)";

var query = Session.CreateQuery(queryString);
query.SetParameterList("positionTypes", positionTypes.Select(pt => pt.SystemName).ToArray());
query.SetParameter("modifiedFrom", modifiedFrom);
query.SetParameter("modifiedTo", modifiedTo);

return query.List<ShipPosition>();

所以问题仍然存在:如何将其转化为使用 QueryOver?

更新 2:
以防万一有人感兴趣,在 MonkeyCoder 的回答帮助下,我将包括我的最终代码的样子:

public IList<ShipPosition> GetModifiedShipPositions(DateTime modifiedFrom, DateTime modifiedTo, params ShipPositionType[] positionTypes)
{
    ShipPosition relatedShipPosition = null;

    var result = Session.QueryOver<ShipPosition>()
        .Left.JoinAlias(sp => sp.RelatedShipPosition, () => relatedShipPosition)
        .WhereRestrictionOn(sp => sp.ShipPositionType).IsInG(positionTypes)
        .And(Restrictions.Or(
            Restrictions.Where<ShipPosition>(sp => sp.ModifiedDate.IsBetween(modifiedFrom).And(modifiedTo)),
            Restrictions.Where(() => relatedShipPosition.ModifiedDate.IsBetween(modifiedFrom).And(modifiedTo))));

    return result.List();
}

【问题讨论】:

  • 感谢您花时间添加更新并发布您的最终答案。 +1

标签: c# nhibernate .net-4.0 queryover nhibernate-3


【解决方案1】:

我不知道你是否已经尝试过这个 - 我无法正确测试这个 - 因为我不在电脑旁,但我认为你可以给试一试:

ShipPosition shipPosition = null;
ShipPositionType shipPositionType = null;
RelatedShipPosition relatedShipPosition = null;

var result = QueryOver.Of<ShipPosition>(() => shipPosition)
    .JoinAlias(() => shipPosition.ShipPositionType, () => shipPositionType)
    .JoinAlias(() => shipPosition.RelatedShipPosition, () => relatedShipPosition)
    .WhereRestrictionOn(() => relatedShipPosition.SystemName).IsInG(positionTypes)
    .And(Restrictions.Or(
        Restrictions.Where(() => shipPosition.ModifiedDate).IsBetween(modifiedFrom).And(modifiedTo)),
        Restrictions.Where(() => relatedShipPosition.ModifiedDate).IsBetween(modifiedFrom).And(modifiedTo));

希望对你有帮助!

【讨论】:

  • 感谢 MonkeyCoder,它帮助我朝着正确的方向前进。我必须在relatedShipPosition 上的.JoinAlias 之前添加一个.Left(并且.IsInGshipPosition 而不是relatedShipPosition),但除此之外它很好:)
  • 谢谢!我很高兴能帮上忙:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-20
  • 1970-01-01
  • 2012-03-06
相关资源
最近更新 更多