为什么这两个Fluent nHibernate查询产生不同的结果?

时间:2012-05-02 08:07:54

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

我一直在努力弄清楚为什么这个要求经理和他或她的团队的查询只返回Team集合的第一个条目。显然,这是因为我在查询结束时有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");

3 个答案:

答案 0 :(得分:3)

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适用于数据库。所有这些都是关于ToList结果的。因此,FirstOrDefault从ToList的结果集中获取FirstOrDefault。要获得相同的结果,您需要为查询添加订单。在没有订单的情况下执行select时,Sql不会对结果集的相同顺序进行授予。 ToList结果中的顺序与第一个查询中的内部顺序不同。

答案 1 :(得分:1)

我一直在努力解决同样的问题。对我来说,这是从NH 3.1升级时发生的 - &gt; 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();

答案 2 :(得分:0)

问题在于我要求使用笛卡尔积(使用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();