Domanda

Ho una tabella di posizioni in cui una posizione può avere una posizione correlata (ma non necessariamente) e ogni posizione ha un'ultima data modificata. Voglio quindi recuperare tutte le posizioni (di un determinato tipo) che è stato modificato tra due date fornite (cioè la posizione "principale" o la posizione correlata è stata modificata). In SQL lo farei come segue:

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

Ora sono abbastanza nuovo a NHibernate (3.0) e queryover, e ho un po 'di problemi a tradurre questa query SQL al codice C#. Ne ho letto un po ' esempi E ho provato a guardare altre domande, ma purtroppo nessuna fortuna.

Il mio tentativo iniziale è stato qualcosa del genere:

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

Ma questo lancia un KeyNotFoundException (la chiave data non era presente nel dizionario). Ho provato a sperimentare JoinQueryOver e JoinAlias Dato che sospetto sia uno di quelli che mancano, ma non sono riuscito a farlo bene.

Se qualcuno potesse indicarmi nella giusta direzione (o in una domanda in cui è già stato risolto), sarei molto grato!

Aggiornare:

Ho provato a scrivere la query 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();

Ciò non ha lanciato alcuna eccezione, ma non ho ottenuto il risultato desiderato (mancando un caso lì p.reatedposition è nullo.

E solo aver detto che, l'uso di HQL funziona bene e dà lo stesso risultato della query 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>();

Quindi la domanda rimane ancora: come posso tradurlo nell'uso di queryover?

Aggiornamento 2:
Nel caso in cui sia interessante per chiunque, includerò l'aspetto del mio codice finale, dopo l'aiuto della risposta di 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();
}
È stato utile?

Soluzione

Non so se hai già provato questo - Non sono in grado di testarlo correttamente - Dato che sono lontano dal mio computer, ma ho pensato che potresti provare:

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

Spero possa essere d'aiuto!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top