【问题标题】:Am I doing something wrong with Nhibernate Query Over fetch?我对 Nhibernate Query Over fetch 做错了吗?
【发布时间】:2011-06-02 23:04:54
【问题描述】:

我有这个

   using (ITransaction transaction = session.BeginTransaction())
        {
            Task tAlias = null;
            CompletedTask cAlias = null;

            List<Task> tasks = session.QueryOver<Task>(() => tAlias)
                .Where(Restrictions.In(Projections.Property(() => tAlias.Course.Id), courseIds))
                .Fetch(pt => pt.PersonalTaskReminders).Eager
                .List<Task>().ToList().ConvertToLocalTime(student);


            transaction.Commit();

            return tasks;
        }

    PersonalTaskReminders == Collection

所以一个任务可以有很多个人任务提醒。我发现如果我设置了 2 个personalTask​​Reminders(所以 PersonalTask​​Reminders 现在将在它的数据库集合中有 2 行)

它两次返回相同的任务。

因此,如果我有 50 个用于该任务的个人任务提醒。我会得到 50 个相同任务的结果。我不明白为什么。

如果我删除了急切加载。我按预期从数据库中取回了一项任务。

【问题讨论】:

    标签: nhibernate fetch eager-loading queryover


    【解决方案1】:

    很明显,因为 Eager fetch 会导致加入 2 个表。要消除重复的结果,您应该使用 DistinctRootEntityTransformer。

    顺便说一句,NHibernate 为IN 子句提供了更好的语法。所以你的查询应该是这样的:

        var tasks = Session.QueryOver<Task>()
                .WhereRestrictionOn(x => x.Id).IsIn(courseIds)
                .Fetch(pt => pt.PersonalTaskReminders).Eager
                .TransformUsing(Transformers.DistinctRootEntity)
                .List<Task>();
    

    【讨论】:

    • @xelibrion - 对你来说可能很明显,但当我通过 nhibernate profiler 看到原始 sql 时,我不知道它为什么要加入。与仅执行 fetch 和 Fetch().Eager 有什么区别?
    • NHibernate 可以通过两种方式加载对象 - 急切加载和延迟加载。急切加载总是会导致连接。延迟加载使用选择查询,经常导致选择 N+1 问题。但是你可以通过在集合映射中指定batch size来获得延迟加载的好处,所以不会导致select N+1问题
    • @xelibrion - 所以 fetch 告诉它做延迟加载?我以为这是默认开启的?
    • Fetch().Eager 告诉做连接。这就是为什么你有重复。
    • @xelibrion - 好的。如果我只是做了 .Fetch() 而没有其他东西会等于延迟加载呢?
    【解决方案2】:

    Xelibrion 的解决方案是解决问题的正确方法。

    要了解为什么在做Fetch的时候结果会重复,可以对比一下生成的SQL:

    没有FetchSELECT 中的字段只是您的根实体Task 字段。

    对于FetchPersonalReminder 实体的字段已添加到SELECT。因此,如果您有两个 PersonalReminder 寄存器用于相同的 Task,您会在结果中得到两个寄存器,并且 DISTINCT 子句不会删除它们(因为实际返回的寄存器不同,因为它们包含 PersonalReminder 字段) .

    使用TransformUsing 和不使用TransformUsing 生成的SQL 完全相同,但NH 会处理返回的寄存器以删除重复项。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多