Pregunta

Tengo una tabla de posiciones donde una posición puede tener una posición relacionada (pero no necesariamente), y cada posición tiene una última fecha modificada. Luego quiero obtener todas las posiciones (de un tipo dado) que se modificó entre dos fechas dadas (es decir, la posición "principal" o la posición relacionada se modificó). En SQL haría esto de la siguiente manera:

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

Ahora soy bastante nuevo en NHibernate (3.0) y Queryover, y tengo un poco de problema en traducir esta consulta SQL al código C#. He leído algunos ejemplos e intenté mirar otras preguntas, pero lamentablemente no tuve suerte.

Mi intento inicial fue algo como esto:

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

Pero esto arroja una Noga KeySfoundException (la clave dada no estaba presente en el diccionario). He intentado experimentar con JoinQueryOver y JoinAlias Como sospecho que es uno de los que faltan, pero no he logrado hacerlo bien.

Si alguien pudiera señalarme en la dirección correcta (o una pregunta en la que esto ya está respondido), ¡estaría muy agradecido!

Actualizar:

Intenté escribir la consulta usando 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();

Eso no arrojó ninguna excepción, pero no obtuve el resultado deseado (me faltaba un caso allí P.RelatedShipposition es nula.

Y solo para haber mencionado eso, usar HQL funciona bien y da el mismo resultado que la consulta 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>();

Entonces, la pregunta sigue siendo: ¿cómo puedo traducir esto en el uso de Queryover?

Actualización 2:
En caso de que sea de interés para cualquiera, incluiré cómo se veía mi código final, después de la ayuda de la respuesta de 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();
}
¿Fue útil?

Solución

No sé si ya lo has probado - No puedo probar esto correctamente - Como estoy lejos de mi computadora, pero pensé que podrías probar:

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

¡Espero que ayude!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top