我有一个位置表,其中一个位置可以具有相关位置(但不一定),并且每个位置都具有最后修改日期。然后,我想要获取在两个给定日期之间修改的所有(给定类型的)位置(即“主”位置或相关位置被修改)。在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(给定的键不在字典中)。我尝试使用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();
}
答案 0 :(得分:2)
我不知道你是否已经尝试过这个 - 我无法正确测试 - 因为我离开了我的电脑,但我想你可以给试一试:
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));
我希望它有所帮助!