Ich habe eine Tabelle von Positionen, wobei eine Position eine verwandte Position haben kann (aber nicht unbedingt), und jede Position hat ein letztes Änderungsdatum. Ich möchte dann alle Positionen (eines bestimmten Typs) abrufen, die zwischen zwei bestimmten Daten geändert wurden (d. H. entweder die "Haupt" -Position oder die verwandte Position wurde geändert). In SQL würde ich das wie folgt tun:
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')
Jetzt bin ich ziemlich neu bei NHibernate (3.0) und QueryOver, und ich habe ein kleines Problem, diese SQL-Abfrage in C#-Code zu übersetzen. Ich habe einige Beispiele gelesen und versucht, andere Fragen anzusehen, aber leider kein Glück.
Mein erster Versuch sah ungefähr so aus:
public IList GetModifiedShipPositions(IList positionTypes, DateTime modifiedFrom, DateTime modifiedTo)
{
var result = Session.QueryOver()
.WhereRestrictionOn(p => p.ShipPositionType).IsInG(positionTypes)
.And(Restrictions.Or(
Restrictions.Where(p => p.ModifiedDate.IsBetween(modifiedFrom).And(modifiedTo)),
Restrictions.Where(p => p.RelatedShipPosition != null
&& p.RelatedShipPosition.ModifiedDate.IsBetween(modifiedFrom).And(modifiedTo))));
return result.List();
}
Aber das wirft eine KeyNotFoundException (Der angegebene Schlüssel war nicht im Wörterbuch vorhanden). Ich habe versucht, mit JoinQueryOver
und JoinAlias
zu experimentieren, da ich vermute, dass eines davon fehlt, aber ich habe es nicht geschafft, es richtig zu machen.
Wenn jemand mich in die richtige Richtung weisen könnte (oder zu einer Frage, in der dies bereits beantwortet wurde), wäre ich sehr dankbar!
Update:
Ich habe versucht, die Abfrage mit Linq zu schreiben:
var query = Session.Query().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();
Das hat keine Ausnahmen ausgelöst, aber ich habe nicht das gewünschte Ergebnis erhalten (ein Fall fehlt, in dem p.RelatedShipPosition null ist.
Und nur um das erwähnt zu haben, mit HQL funktioniert einwandfrei und liefert das gleiche Ergebnis wie die SQL-Abfrage:
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();
Die Frage bleibt also bestehen: Wie kann ich dies in QueryOver übersetzen?
Update 2:
Nur für den Fall, dass es jemanden interessiert, werde ich zeigen, wie mein endgültiger Code nach Hilfe aus der Antwort von MonkeyCoder aussah:
public IList GetModifiedShipPositions(DateTime modifiedFrom, DateTime modifiedTo, params ShipPositionType[] positionTypes)
{
ShipPosition relatedShipPosition = null;
var result = Session.QueryOver()
.Left.JoinAlias(sp => sp.RelatedShipPosition, () => relatedShipPosition)
.WhereRestrictionOn(sp => sp.ShipPositionType).IsInG(positionTypes)
.And(Restrictions.Or(
Restrictions.Where(sp => sp.ModifiedDate.IsBetween(modifiedFrom).And(modifiedTo)),
Restrictions.Where(() => relatedShipPosition.ModifiedDate.IsBetween(modifiedFrom).And(modifiedTo))));
return result.List();
}