【问题标题】:Why do these two Fluent nHibernate queries produce different results?为什么这两个 Fluent nHibernate 查询会产生不同的结果?
【发布时间】:2012-05-02 08:07:53
【问题描述】:

我一直在试图弄清楚为什么这个查询经理和他或她的团队只返回团队集合的第一个条目。显然,这是因为我在查询末尾有 FirstOrDefault 。我的印象是 FirstOrDefault 将应用于整个查询,但它似乎也应用于 Team 集合。

原始查询(仅显示团队中的第一个成员):

  session.Query<IEmployee>()
                .Where(p => p.PersonalNumber == PersonalNumber)
                .Fetch(p => p.Team)
                .Fetch(p => p.Manager)
                .FirstOrDefault();

返回完整团队的新查询:

  session.Query<IEmployee>()
                .Where(p => p.PersonalNumber == PersonalNumber)
                .Fetch(p => p.Team)
                .Fetch(p => p.Manager)
                .ToList().FirstOrDefault();

制定此查询的正确方法是什么?我需要解决方法意味着我没有正确执行此操作。

背景 - 映射:

这是一个基本的层次关系,Manager 是一个 IEmployee,Team 是一个 IEmployee 的 IList。

References(x => x.Manager).Column("ManagerId");
HasMany(x => x.Team)
                .AsList(index => index.Column("TeamIndex"))
                .KeyColumn("ManagerId");

【问题讨论】:

  • 您可以从生成的 SQL 中看出这是如何发生的,因为问题查询生成了 sql “FETCH NEXT 1 ROWS ONLY”,这大概意味着只会返回第一个连接记录。我不清楚的是如何让 FirstOrDefault 与 Fetch 一起正常工作。

标签: nhibernate fluent-nhibernate fluent-nhibernate-mapping


【解决方案1】:
session.Query<IEmployee>()
            .Where(p => p.PersonalNumber == PersonalNumber)
            .Fetch(p => p.Team)
            .Fetch(p => p.Manager)
            .FirstOrDefault();

在此查询中,FirstOrDefault 按您的预期在数据库上工作。

session.Query<IEmployee>()
            .Where(p => p.PersonalNumber == PersonalNumber)
            .Fetch(p => p.Team)
            .Fetch(p => p.Manager)
            .ToList().FirstOrDefault();

在此查询中,ToList 对数据库起作用。 All behind 对 ToList 的结果起作用。所以 FirstOrDefault 从 ToList 的结果集中获取 FirstOrDefault。要获得相同的结果,您需要在查询中添加订单。当您进行无顺序选择时,Sql 不会授予结果集的相同顺序。 ToList 结果中的顺序与第一个查询中的内部顺序不同。

【讨论】:

  • 对不起,我不太明白。结果集的顺序(始终只包含 1 个 IEmployee,PersonalNumber 是唯一的)将如何影响 Employee.Team 集合中的项目数?
【解决方案2】:

我一直在努力解决同样的问题。对我来说,这发生在从 NH 3.1 -> 3.3 升级时。问题在于,使用 Linq,NHibernate 3.3 会生成一个 SQL 查询,其中包含“Top(1)”语句,从而有效地终止了查询的“Fetch”部分。我通过从 Linq 切换到 QueryOver 解决了这个问题。我相信这会奏效:

  session.QueryOver<IEmployee>()
                .Where(p => p.PersonalNumber == PersonalNumber)
                .Fetch(p => p.Team)
                .Fetch(p => p.Manager)
                .SingleOrDefault();

【讨论】:

  • 有趣,这本质上也是我在一些实验后注意到的(见下面我的回答),是的,我使用的是 nHibernate 3.3。我想知道原始语法是否应该抛出某种异常,说它是无效的。
【解决方案3】:

问题是我要求笛卡尔积(使用 Fetch)但也使用 FirstOrDefault;从生成的 SQL 中,我可以看到该组合不起作用,因为您只得到笛卡尔积的第一行(生成的 SQL:“FETCH NEXT 1 ROWS ONLY”)。

如果我想这样做,我将需要编写一种不同类型的查询,或者只使用 ToList 解决方法,在这种情况下不会造成太大的伤害,因为无论如何我只期望来自数据库的一个结果。

示例解决方案:

session.QueryOver<IEmployee>()
                .Where(p => p.PersonalNumber == PersonalNumber)
                .Fetch(p => p.Team).Eager
                .Fetch(p => p.Manager).Eager
                .SingleOrDefault();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-11
    • 1970-01-01
    • 1970-01-01
    • 2013-08-15
    相关资源
    最近更新 更多