2015-02-23 16 views
0

我有以下映射類中定義負荷僅在SQLAlchemy的ORM加入行的子集

class A(Base): 
    __tablename__ = "a" 
    id = sqla.Column(sqla.Integer, primary_key = True) 
    number_a = sqla.Column(sqla.Integer) 
    b_collection = relationship('B', backref = backref('a')) 

class B(Base): 
    __tablename__ = "b" 
    id = sqla.Column(sqla.Integer, primary_key = True) 
    id_a = sqla.Column(sqla.Integer, sqla.ForeignKey('a.id')) 
    number_b = sqla.Column(sqla.Integer) 

有這些對象存儲在數據庫中:

a1 = A(number_a = 1) 
a2 = A(number_a = 2) 
b1 = B(number_b = 50, a = a2) 
b2 = B(number_b = 51, a = a2) 

我需要的是查詢的關係只發放,使其通過該查詢的結果僅預裝b_collection一個查詢:

result = session.query(A).join(B).filter(B.number_b == 51).all() 

所以現在我想result[0].b_collection尊重過濾表達式,不包括B實例with number_b = 50。所以我預期的輸出:

for a in result: 
    for b in a.b_collection: 
     print(b.number_b) 

是:

51 

但是迭代throught a.b_collection八方通發佈新的查詢和負載都B對象爲b_collection,這樣的結果是

50 
51 

這是我不想得到的。

如何執行原始查詢來加載所有對象並根據給定的過濾條件填充關係集合?

感謝您的回覆。

回答

1

爲此,使用contains_eager,但要知道,你是欺騙 SQL鍊金術,所以不要重用此的UnitOfWork做常規關係相關的任務:

result = (
    session.query(A) 
    .join(B) 
    .filter(B.number_b == 51) 
    .options(contains_eager(A.b_collection)) # this is the key 
    ).all() 
+0

謝謝,這作品!它在什麼意義上?有什麼危險? – 2015-02-23 17:52:55

+0

你正在欺騙'session'來認爲你*加載了'A.b_collection'關係。因此,如果您對其執行操作,那麼它們並不代表後端數據庫的狀態。 – van 2015-02-23 18:26:24

+0

是的,那是對的。瞭解。感謝您的警告和解決方案。 – 2015-02-23 21:27:26