NHibernate QueryOver с левой самостоятельной регистрации - PullRequest
3 голосов
/ 09 сентября 2011

У меня есть таблица позиций, где позиция может иметь связанную позицию (но не обязательно), и каждая позиция имеет дату последнего изменения. Затем я хочу получить все позиции (заданного типа), которые были изменены между двумя указанными датами (т.е. была изменена либо «основная» позиция, либо связанная с ней позиция). В 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 #. Я прочитал примеры и попытался посмотреть на другие вопросы, но, к сожалению, не повезло.

Моя первая попытка была примерно такой:

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 (указанный ключ отсутствует в словаре). Я попытался поэкспериментировать с JoinQueryOver и JoinAlias, так как подозреваю, что это один из тех, которые отсутствуют, но мне не удалось сделать это правильно.

Если бы кто-нибудь мог указать мне правильное направление (или на вопрос, на который уже дан ответ), я был бы очень признателен!

Обновление:

Я пытался написать запрос, используя 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 равно нулю.

И только что упомянул, что использование 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 Ответ

2 голосов
/ 09 сентября 2011

Я не знаю, пробовали ли вы уже это - Я не могу проверить это должным образом - так как я далеко от своего компьютера, но я думаю, что вы могли бы дать попробовать:

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));

Надеюсь, это поможет!

...