1

我正在大量使用 subqueryload/subqueryload_all,并且遇到了边缘情况,我倾向于非常明确地定义在 subqueryload 期间使用的查询。例如,我有一个帖子和评论的情况。我的查询看起来像这样:

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

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

我想做的是明确定义 subqueryload/subqueryload_all 用来加载帖子评论的查询。我在这里读到了 DisjointedEagerLoading ,看起来我可以简单地定义一个特殊的函数来接收基本查询,以及一个加载指定关系的查询。这是解决这种情况的好方法吗?以前有人遇到过这种边缘情况吗?

4

2 回答 2

2

答案是可以在Posts 和Comments 之间定义多个关系:

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其他地方使用现有关系。

于 2013-10-01T12:29:43.500 回答
1

我也遇到了这个问题,我花了一些时间才意识到这是一个设计问题。当您说Post.commentsthen 您指的是“这些都是该帖子的所有评论”的关系。但是,现在您要过滤它们。如果您现在在某处指定该条件,subqueryload那么您实际上只是将值的子集加载到Post.comments. 因此,将缺少值。本质上,您在模型中的数据表示错误。

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

但是还有改进的余地:您可能希望将此附加到您的课程中,这样您就不会携带两个变量。简单的方法可能是定义第二个关系,例如published_comments指定额外参数。然后,您还可以控制没有人写入它,例如使用属性 events。在这些事件中,您可以处理允许操作的方式,而不是禁止操作。唯一的问题可能是更新发生时,例如,当您添加评论时,Post.commentspublished_comments不会自动更新,因为它们彼此不知道。同样,如果这是必需的功能,我会为此采取事件(但使用上述丑陋的解决方案,您也不会拥有)。

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

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

于 2013-10-01T12:17:37.950 回答