SqlAlchemy:检查一个对象是否存在任何关系(or_(object.relationship1.contains(otherObject), object.relationship2.contains(otherObject))

发布于 2024-11-09 06:00:43 字数 1036 浏览 2 评论 0原文

假设我有一个这样的类:(

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,所以第二个过滤器给出空结果。

我已经能够找到子查询的解决方法(子查询中的每个 join+filter,然后 or_ 所有子查询),但我想知道是否有更好的方法来做到这一点......

我发现了这个: http://techspot.zzzeek.org/2008/09/09/selecting- booleans/

这就是我想做的,但它是针对 SqlAlchemy 0.5 的,我(几乎)确定有一种“更干净”的方法可以用 SqlAlchemy 0.6.6 来完成它,

谢谢!

Let's say I have a class like this:

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())

(Each of the relationships gives me "Bar"s with a certain conditions). At a certain point, I want to get instances of "Foo"s that have a "bar" (instance of Bar.Bar) in any of the relationships.

If I try to do:

def inAnyBar(bar)
   query(Foo).filter(or_(Foo.bars1.contains(bar), Foo.bars2.contains(bar)).all()

I get an empty result.

It looks (to me) like I'm doing something like:

query(Foo).join(Foo.bars1).filter(Foo.bars1.contains(bar)).\
join(Foo.bars2).filter(Foo.bars1.contains(bar))

Since Foo.bars1 doesn't contain bar, the second filter gives empty results.

I've been able to find a workaround with subqueries (each join+filter in a subquery, then or_ all the subqueries) but I'd like to know if there's a better way to do it...

I found this:
http://techspot.zzzeek.org/2008/09/09/selecting-booleans/

That does what I want to do, but it's for SqlAlchemy 0.5 and I'm (almost) certain that there's a "cleaner" way to do it with SqlAlchemy 0.6.6

Thank you!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

意中人 2024-11-16 06:00:43

你是对的, 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

当以下之一时返回不正确的结果辅助 表为空。看起来像是 SQLAlchemy 中的一个错误。但是,用 any() 替换 contains() 解决了问题(它使用 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))

You are right, session.query(Foo).filter(Foo.bars1.contains(bar)|Foo.bars2.contains(bar)) produces the following 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

which returns incorrect result when one of the secondary tables is empty. Seems like a bug in SQLAlchemy. However replacing contains() with any() fixed the problem (it uses EXISTS subqueries):

session.query(Foo).filter(Foo.bars1.any(id=bar.id)|Foo.bars2.any(id=bar.id))

Also you can specify OUTER JOIN explicitly:

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))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文