代码之家  ›  专栏  ›  技术社区  ›  JayD3e

如何显式定义subqueryload_all中使用的查询?

  •  1
  • JayD3e  · 技术社区  · 11 年前

    我非常频繁地使用subqueryload/subqueryload_all,并且遇到了边缘情况,在这种情况下,我往往需要非常明确地定义在subqueryload期间使用的查询。例如,我有一种情况,我有帖子和评论。我的查询如下所示:

    posts_q = db.query(Post).options(subqueryload(Post.comments))
    

    正如你所看到的,我正在加载每个帖子的评论。问题是,我不想要所有帖子的评论,我还需要考虑一个已删除的字段,并且它们需要按创建时间降序排列。我观察到的唯一方法是将选项添加到 relationship() 帖子和评论之间的声明。我宁愿不这样做,b/c这意味着在那之后,这种关系不能在任何地方重复使用,因为我在应用程序中的其他地方可能不适用这些限制。

    我想做的是明确定义subqueryload/subjqueryload_all用来加载帖子评论的查询。我读到关于DisjointedEagleLoading的文章 here ,看起来我可以简单地定义一个特殊的函数来接受基本查询,以及一个加载指定关系的查询。对于这种情况,这是一条好的路线吗?以前有人遇到过这种边缘案件吗?

    2 回复  |  直到 11 年前
        1
  •  2
  •   EoghanM    11 年前

    答案是,您可以定义 Post s和 Comment 秒:

    class Post(...):
        active_comments = relationship(Comment,
             primary_join=and_(Comment.post_id==Post.post_id, Comment.deleted=False),
             order_by=Comment.created.desc())
    

    然后,您应该能够通过该关系进行子查询加载:

    posts_q = db.query(Post).options(subqueryload(Post.active_comments))
    

    您仍然可以使用现有的 .comments 其他地方的关系。

        2
  •  1
  •   javex    11 年前

    我也有这个问题,我花了一些时间才意识到这是一个设计问题。当你说 Post.comments 然后你提到关系,上面写着“这些都是那篇帖子的评论”。但是,现在您要过滤它们。如果你现在在某个地方指定这个条件 subqueryload 那么您实际上只将值的子集加载到 邮局 因此,将缺少值。从本质上讲,模型中的数据表示有误。

    这里的问题是如何处理这个问题,因为你显然需要这个值 在某处 。我的方法是自己构建子查询,然后在那里指定特殊条件。这意味着你会得到两个对象:帖子列表和评论列表。这不是一个很好的解决方案,但至少它没有以错误的方式显示数据。如果您要访问 邮局 出于某种原因,您可以放心地假设它包含所有帖子。

    但还有改进的空间:你可能想把这个附加到你的课上,这样你就不会有两个变量了。简单的方法可能是定义第二种关系,例如。 published_comments 其指定额外的参数。然后,您还可以控制没有人向其写入,例如使用 attribute events 在这些情况下,你可以处理如何允许操纵,而不是禁止操纵。唯一的问题可能是当更新发生时,例如当您向添加评论时 邮局 然后 已发布评论 不会自动更新,因为他们不知道彼此。同样,如果这是一个必需的功能,我会为此接受事件(但对于上面丑陋的解决方案,你也不会有)。

    作为最后一个混合解决方案,您可以采取第一种方法,然后将这些值分配给您的对象,例如。 Post.deleted_comments = deleted_comments .

    这里需要记住的是,操作ORM生成的查询通常不是一个聪明的主意,因为这可能会导致以后出现问题 contains_eager 这很容易实现),但它在某些方面造成了问题(虽然通常是功能性的),所以我放弃了这种方法。