SqlAlchemy:检查对象是否在任何关系中 (or_(object.relationship1.contains(otherObject), object.relationship2.contains(otherObject))
假设我有一个这样的类:
class Foo(declarativeBase):
bars1 = relationship(Bar.Bar, secondary=foos_to_bars1, collection_class=set())
bars2 = relationship(Bar.Bar, secondary=foos_to_bars2, collection_class=list())
(每个关系都会给我一些“Bar”,并且有特定的条件)。在某个时刻,我想获取那些在任何关系中都有“bar”(Bar.Bar的实例)的“Foo”的实例。
如果我尝试这样做:
def inAnyBar(bar)
query(Foo).filter(or_(Foo.bars1.contains(bar), Foo.bars2.contains(bar)).all()
我得到的结果是空的。
在我看来,这就像是:
query(Foo).join(Foo.bars1).filter(Foo.bars1.contains(bar)).\
join(Foo.bars2).filter(Foo.bars1.contains(bar))
因为Foo.bars1里没有bar,所以第二个过滤条件的结果是空的。
我找到了一种解决方法,就是使用子查询(每个连接+过滤放在一个子查询中,然后把所有子查询用or连接起来),但我想知道有没有更好的方法来实现这个...
我发现了这个链接:
http://techspot.zzzeek.org/2008/09/09/selecting-booleans/这个方法可以实现我想做的事情,但它是针对SqlAlchemy 0.5的,而我(几乎)确定在SqlAlchemy 0.6.6中有更“干净”的方法来做到这一点。
谢谢!
1 个回答
4
你说得对,session.query(Foo).filter(Foo.bars1.contains(bar)|Foo.bars2.contains(bar))
生成了以下的 SQL 语句:
SELECT "Foo".id AS "Foo_id"
FROM "Foo", foos_to_bars1 AS foos_to_bars1_1, foos_to_bars2 AS foos_to_bars2_1
WHERE "Foo".id = foos_to_bars1_1.foo AND ? = foos_to_bars1_1.bar OR
"Foo".id = foos_to_bars2_1.foo AND ? = foos_to_bars2_1.bar
当其中一个 secondary
表是空的时候,这个查询会返回错误的结果。看起来这是 SQLAlchemy 的一个 bug。不过,把 contains()
换成 any()
就解决了这个问题(因为它使用了 EXISTS 子查询):
session.query(Foo).filter(Foo.bars1.any(id=bar.id)|Foo.bars2.any(id=bar.id))
另外,你也可以明确指定 OUTER JOIN:
Bar1 = aliased(Bar)
Bar2 = aliased(Bar)
session.query(Foo).outerjoin((Bar1, Foo.bars1)).outerjoin((Bar2, Foo.bars2))\
.filter((Bar1.id==bar.id)|(Bar2.id==bar.id))