NHibernate QueryOver 与左自连接

发布于 2024-12-03 11:16:44 字数 3769 浏览 2 评论 0原文

我有一个职位表,其中一个职位可以有一个相关职位(但不一定),并且每个职位都有最后修改日期。然后,我想获取在两个给定日期之间修改的所有位置(给定类型)(即“主要”位置或相关位置被修改)。在 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 (给定的键不存在于字典中)。我尝试过使用 JoinQueryOverJoinAlias 进行实验,因为我怀疑它是缺少的其中之一,但我还没有成功。

如果有人能指出我正确的方向(或已经回答的问题),我将非常感激!

更新:

我尝试使用 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 为 null。

刚刚提到使用 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();
}

I have a table of positions where a position can have a related position (but not necessarily), and every position has a last modified date. I then want to fetch all positions (of a given type) that was modified between two given dates (i.e. either the "main" position or the related position was modified). In SQL I would do this as follows:

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

Now I'm fairly new to NHibernate (3.0) and QueryOver, and I have a bit of a problem translating this SQL query to C# code. I have read some examples and tried looking at other questions, but sadly no luck.

My initial attempt was something like this:

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

But this throws a KeyNotFoundException (The given key was not present in the dictionary). I have tried experimenting with JoinQueryOver and JoinAlias as I suspect it's one of those that are missing, but I haven't managed to get it right.

If anybody could point me in the right direction (or to a question where this is already answered), I would be very grateful!

Update:

I tried writing the query using 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();

That didn't throw any exceptions, but I didn't get the desired result (missing one case there p.RelatedShipPosition is null.

And just to have mentioned that, using HQL works fine and gives the same result as the SQL query:

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

So the question still remains: how can I translate this into using QueryOver?

Update 2:
Just in case it is of interest to anybody, I'll include what my final code looked like, after help from MonkeyCoder's answer:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

故事与诗 2024-12-10 11:16:44

我不知道您是否已经尝试过这个 - 我无法正确测试 - 因为我离开了我的计算机,但我认为您可以尝试一下:

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

我希望它有帮助!

I don't know if you've already tried this one out - I'm unable to test this properly - as I'm away from my computer, but I though that you could give a try:

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

I hope it helps!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文