简体   繁体   English

如何使用在 SQLAlchemy 和 contains_eager 关系上定义的 order_by?

[英]How to use the order_by defined on the relationship in SQLAlchemy and contains_eager?

The Zen of Joined Eager Loading docs recommends using contains_eager() if we want to keep the relationship order defined in the model. Zen of Joined Eager Loading docs 推荐使用contains_eager()如果我们想保持模型中定义的关系顺序。

"If we wanted to use just one JOIN for collection loading as well as ordering, we use the contains_eager() option, described in Routing Explicit Joins/Statements into Eagerly Loaded Collections below." “如果我们只想使用一个 JOIN 进行集合加载和排序,我们可以使用 contains_eager() 选项,如下文将显式连接/语句路由到 Eagerly Loaded 集合中所述。”

But the following example seems to behave otherwise.但下面的例子似乎表现得不一样。 I must be missing something, but unsure what.我一定错过了什么,但不确定是什么。

class Parent(Base):
    __tablename__ = "parent"

    parent_id = Column(types.Integer, primary_key=True)
    name = Column(types.String(200), nullable=False)


class Child(Base):
    __tablename__ = "child"

    order = Column(types.Integer, default=0)
    name = Column(types.String(200))

    parent_id = Column(types.Integer, ForeignKey(Parent.parent_id))
    parent = relationship(
        Parent,
        backref=backref(
            "children",
            cascade="all,delete",
            order_by="Child.order",
        ),
    )
query = session.query(Parent).options(
    contains_eager(Parent.children)
).filter(Parent.parent_id == 99).filter(Child.name == "foo")

Generates the following SQL:生成以下 SQL:

SELECT parent.parent_id, parent.name,
       child.order, child.name,
FROM parent, child
WHERE parent.parent_id = 99 AND parent.name = 'foo'

For some reason,因为某些原因,

ORDER BY child.order

is missing, even though it's defined in the relationship() .丢失了,即使它是在relationship()定义的。 Any hints?任何提示?

It works fine if the order_by is specified at query time, but I want to avoid writing the same ordering criteria multiple times.如果在查询时指定 order_by,它工作正常,但我想避免多次编写相同的排序条件。

The documentation is correct, and it refers to the fact that if using most out-of-the box eager loading methods, the query is modified and might not be optimal.文档是正确的,它指的是如果使用大多数开箱即用的急切加载方法,查询会被修改并且可能不是最佳的。

The suggestion is then to use contains_eager where:然后建议使用contains_eager ,其中:

1) the user is responsible for constructing the correct query (including joins, filters, ordering etc) 1) 用户负责构造正确的查询(包括连接、过滤器、排序等)

2) by using contains_eager the user hints SA that the specified relationship is included in the query. 2) 通过使用contains_eager用户提示SA 指定的关系包含在查询中。


The way to load relationship eagerly would be to use joinedload :急切加载关系的方法是使用joinedload

q_joined = (
    session
    .query(Parent)
    .options(joinedload(Parent.children))
    .filter(Parent.parent_id == parent_id)
)

But you cannot apply these additional filters in this case.但是在这种情况下您不能应用这些附加过滤器。

Using the contains_eager you would do:使用contains_eager你会这样做:

q_manual = (
    session
    .query(Parent)
    .join(Child)  # MUST HAVE THIS
    .options(contains_eager(Parent.children))
    .filter(Parent.parent_id == 99)
    # .filter(Child.name == "foo")  # you can add this, but you are "tricking" SA into believing that only these 'Child' are part of the Parent.children relationship.
    .order_by(Parent.parent_id, Child.order)  # JUST ADD THIS to solve the ordering
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM