Sql NHibernate中三路多对多对一的映射和查询

Sql NHibernate中三路多对多对一的映射和查询,sql,nhibernate,orm,mapping,Sql,Nhibernate,Orm,Mapping,更新: 我错误地粘贴了来自错误重载的查询代码。底部是固定代码 嗨,假设这是我的域名 我在跟踪一些体育赛事,比如说汽车比赛 每场比赛都有参加比赛的选手 赛车手是特定比赛中的车手(它有车手、起始车道、跑步时间等) 司机有名字等。。。典型的个人数据 我要执行以下查询: 让我了解本次赛事中的所有比赛(让我们不进行分页),显示参赛者信息,包括从车手处获取的数据 我的问题是,我不认为我的映射(或条件查询,或两者)对于这个场景是最优的,所以我想问你,如果你看到这里有任何优化的机会。 我特别不喜欢这样一个事实,

更新: 我错误地粘贴了来自错误重载的查询代码。底部是固定代码

嗨,假设这是我的域名

我在跟踪一些体育赛事,比如说汽车比赛

每场比赛都有参加比赛的选手

赛车手是特定比赛中的车手(它有车手、起始车道、跑步时间等)

司机有名字等。。。典型的个人数据

我要执行以下查询: 让我了解本次赛事中的所有比赛(让我们不进行分页),显示参赛者信息,包括从车手处获取的数据

我的问题是,我不认为我的映射(或条件查询,或两者)对于这个场景是最优的,所以我想问你,如果你看到这里有任何优化的机会。 我特别不喜欢这样一个事实,即当我认为一个子查询只需一次就可以工作时,当前需要对数据库进行两次往返

下面是我的映射和查询(DB是从映射生成的)

第二个问题:

SELECT contestant0_.Race           as Race2_,
       contestant0_.Id             as Id2_,
       contestant0_.Id             as Id0_1_,
       contestant0_.Race           as Race0_1_,
       contestant0_.Lane           as Lane0_1_,
       contestant0_.Driver         as Driver0_1_,
       contestant0_.FinishPosition as FinishPo5_0_1_,
       contestant0_.Finished       as Finished0_1_,
       driver1_.Id                 as Id3_0_,
       driver1_.Name               as Name3_0_
FROM   Racers contestant0_
       left outer join Drivers driver1_
         on contestant0_.Driver = driver1_.Id
WHERE  contestant0_.Race in ('4157280d-be8d-44be-8077-a770ef7cd394' /* @p0 */,'74e1bfaa-9926-43c7-8b17-e242634dc32f' /* @p1 */,'e1e86b67-2c37-4fbe-8793-21e84a6e4be4' /* @p2 */)
试试这个:

DetachedCriteria criteria = DetachedCriteria.For( typeof( Race ), "race" )
    .CreateAlias("Event", "event")
    .CreateAlias("race.Contestants", "contestant")
    .SetFetchMode("race.Contestants", FetchMode.Join)
    .SetFetchMode("contestant.Driver", FetchMode.Join)
    .Add( Restrictions.Eq( "event.EventId", eventId ) )
    .AddOrder<Race>( r => r.Time, Order.Desc )
    .SetResultTransformer( new DistinctRootEntityResultTransformer() )
    .SetFirstResult( firstRaceToFetch )
    .SetMaxResults( count );
return this.ExecuteListQuery<Race>(criteria); }
DetachedCriteria=DetachedCriteria.For(种族类型),“种族”)
.CreateAlias(“事件”、“事件”)
.CreateAlias(“种族、参赛者”、“参赛者”)
.SetFetchMode(“race.competities”,FetchMode.Join)
.SetFetchMode(“竞争者.驱动程序”,FetchMode.Join)
.Add(Restrictions.Eq(“event.EventId”,EventId))
.AddOrder(r=>r.Time,Order.Desc)
.SetResultTransformer(新DistincTrotentyResultTransformer())
.SetFirstResult(firstRaceToFetch)
.SetMaxResults(计数);
返回此.ExecuteListQuery(条件);}
它应该只进行一次查询,然后加入比赛、事件和参赛者

您不应该使用FetchMode。加入太多,返回的结果集会更大。(包括比赛和赛事信息的次数与参赛者的次数一样多。)

Stefan(请退出评论,因为这在目前不是很有用)

我根据您的建议重新编写了代码(没有更改任何映射),现在,查询只返回一个种族-三个种族中的第一个(分页设置为3个种族/页)与查询匹配

当我移除

SetResultTransformer( new DistinctRootEntityResultTransformer() )

我有三个项目,但它的价值是相同的三倍,这是。。。奇怪的有什么想法吗?

我认为它会创建多个查询,以避免重复的内容潜入分页查询。(但我不确定,我还没有看到nhibernate的内部源代码)。对包含重复项的集合进行分页以供实体获取,因为使用了联接,这实际上是无用的,因此您需要确保返回的resultset没有重复项。我认为nhibernate在这里选择2个或更多查询,而不是1个查询

你也加入了驱动程序吗?Stefan,对不起-我粘贴了我的存储库方法的错误重载代码。现在看看固定的代码。是的,我隐式地加入了驱动程序-请看映射:@Krzysztof:我不建议这样做,它总是加入的。在许多情况下,两个查询比一个查询更快,因此我不会将其放入映射文件中。我修复了查询。如果我从Racer映射中删除驱动程序上的fetch=“join”,并执行此代码,它将对每个驱动程序执行单独的查询(NHProf中的N+1警告),并且它还只返回一个race,即setMaxResultEnteresting请求的isntead为3。如果我把它改为Set而不是List,NH将保证没有重复项。我得试一试。谢谢你,弗兰斯。为什么我觉得你的设计有严重的问题,例如,车手和车手之间的模糊性,以及车手仅仅是特定比赛中车手的列表。我们在这里使用的是NASCAR命名法(例如,NEXTEL杯由许多赛道上的许多比赛组成),而不是F1/WRC?1事件==1轨道?好吧,我并没有发明这个命名法,我在关注我的问题领域。这不是这里最相关的;)这是很久以前的事了(我实际上要删除我没有得到任何投票的答案),问题是,如果将FetchMode设置为FetchMode.Join,NH只生成一个带有连接的查询来获取引用的项。此查询返回根实体的次数与返回子实体的次数相同。NH不会自动清理这些。您需要告诉它使用结果转换器来执行此操作。这可能看起来没有必要。但如果您编写了一些复杂的查询,而不希望NH添加一些巫毒逻辑,那么您会对此感到高兴。
SELECT contestant0_.Race           as Race2_,
       contestant0_.Id             as Id2_,
       contestant0_.Id             as Id0_1_,
       contestant0_.Race           as Race0_1_,
       contestant0_.Lane           as Lane0_1_,
       contestant0_.Driver         as Driver0_1_,
       contestant0_.FinishPosition as FinishPo5_0_1_,
       contestant0_.Finished       as Finished0_1_,
       driver1_.Id                 as Id3_0_,
       driver1_.Name               as Name3_0_
FROM   Racers contestant0_
       left outer join Drivers driver1_
         on contestant0_.Driver = driver1_.Id
WHERE  contestant0_.Race in ('4157280d-be8d-44be-8077-a770ef7cd394' /* @p0 */,'74e1bfaa-9926-43c7-8b17-e242634dc32f' /* @p1 */,'e1e86b67-2c37-4fbe-8793-21e84a6e4be4' /* @p2 */)
DetachedCriteria criteria = DetachedCriteria.For( typeof( Race ), "race" )
    .CreateAlias("Event", "event")
    .CreateAlias("race.Contestants", "contestant")
    .SetFetchMode("race.Contestants", FetchMode.Join)
    .SetFetchMode("contestant.Driver", FetchMode.Join)
    .Add( Restrictions.Eq( "event.EventId", eventId ) )
    .AddOrder<Race>( r => r.Time, Order.Desc )
    .SetResultTransformer( new DistinctRootEntityResultTransformer() )
    .SetFirstResult( firstRaceToFetch )
    .SetMaxResults( count );
return this.ExecuteListQuery<Race>(criteria); }
SetResultTransformer( new DistinctRootEntityResultTransformer() )