2017-01-25 9 views
1

私はポニーを使い始めましたが、まだ実際にジョインを使う方法を理解していません。例では、left_join()が2つのfor節で使用されたときに見ましたが、私のコードでそれを繰り返そうとすると、 "コレクションが期待されていました"というメッセージが表示されます。 誰かがそれを使用するか、既に説明されているドキュメントのページを指摘してください。ポニーORM JOINの構文

答えて

6

は、我々は次のエンティティを持っているとしましょう:

from pony import orm 

db = orm.Database() 

class Person(db.Entity): 
    id = orm.PrimaryKey(int, auto=True) 
    name = orm.Required(str) 
    age = orm.Required(int) 
    contacts = orm.Set('Contact') 

class Contact(db.Entity): 
    id = orm.PrimaryKey(int, auto=True) 
    person = orm.Required('Person') 
    type = orm.Required(str) 
    value = orm.Required(str) 

db.generate_mapping(create_tables=True) 

with orm.db_session: 
    john = Person(name='John', age=23) 
    mary = Person(name='Mary', age=21) 
    mike = Person(name='Mike', age=18) 
    arthur = Person(name='Arthur', age=25) 

    john.contacts.create(type='mobile', value='1234567') 
    john.contacts.create(type='email', value='[email protected]') 

    mary.contacts.create(type='mobile', value='76543321') 
    mary.contacts.create(type='skype', value='mary123') 

    mike.contacts.create(type='mobile', value='2345678') 

は今、我々はそれを行うことができますどのようにいくつかの方法があります20.その後、高齢者名とそれぞれの人のための連絡先情報を印刷したいです。


最初の方法は、結合条件を明示的に指定することです。この方法はかなり冗長です。

query = orm.select(
    (p.name, c.value) 
    for p in Person for c in Contact 
    if p.age > 20 and c.person == p 
) 
query.show() 

このクエリでは、明示的に結合条件:c.person == pを指定しています。あなたが見ることができるように彼の年齢は、これは参加のこのタイプは、内側であるから参加され、その結果20よりも大きいとはいえ、アーサーは、結果に含まれていなかった

p.name|c.type|c.value 
------+------+---------------- 
John |email |[email protected] 
John |mobile|1234567 
Mary |mobile|76543321 
Mary |skype |mary123 

:クエリは、私たちに次のような結果が表示されます少なくとも1人の連絡先を見つけることができた人のみが含まれています。


参加の第二の方法は、コレクション属性の上に私たちのループときです:

query = orm.select(
    (p.name, c.value) 
    for p in Person for c in p.contacts 
    if p.age > 20 
) 
query.show() 

加入のこのタイプは最も頻繁に使用されています。結合条件を明示的に指定する必要がないので、非常に便利です。クエリの結果は前と同じである:

p.name|c.type|c.value 
------+------+---------------- 
John |email |[email protected] 
John |mobile|1234567 
Mary |mobile|76543321 
Mary |skype |mary123 

アーサーは前と同じ理由でリストにはまだありません。我々は結果にアーサーを含めたい場合は、我々は参加の他のタイプを使用する必要がある、すなわち、加入左:その場合は

query = orm.left_join(
    (p.name, c.value) 
    for p in Person for c in p.contacts 
    if p.age > 20 
) 
query.show() 

クエリの結果ではなく、電話番号のなし値とアーサーが含まれています

p.name|c.type|c.value 
------+------+---------------- 
Arthur|None |None 
John |email |[email protected] 
John |mobile|1234567 
Mary |mobile|76543321 
Mary |skype |mary123 

left_joinを使用する場合、コレクションをループする必要があります。その場合、Ponyは、SQLコマンドのLEFT JOIN節のONセクションに結合条件を追加します。その場合にはポニーがLEFT JOIN句のONセクションに置くことである状態を知らないので、あなたが、left_joinを使用する場合は、明示的に行うことはできません

は非常に最初のクエリのように参加します。

ONセクションの内容を手動で指定すると便利な場合があります。現在、Ponyはそのようなクエリをサポートしていませんが、この機能は将来追加される可能性があります。


多くの場合、PonyORMを使用すると、結合を一切行わずにデータを取得することができます。それぞれの人の連絡先が別のSQLによって取得され、これは「N + 1クエリ」につながる他のORMの問題では、

with db_session: 
    for p in Person.select(lambda p: p.age > 20): 
     print(p.name) 
     for c in p.contacts: 
      print(c.type, c.value) 

:たとえば、あなたは人の名前と電話番号を印刷するには、次のループを書くことができますクエリ。 Ponyは自動的にクエリを最適化して "N + 1クエリ"パターンを回避しようとします。


場合によっては、結合が暗黙的です。たとえば、名前「M」で開始された人のすべての連絡先を見つけるために、次のように記述することができます:Personテーブルが暗黙的に接合され、その場合には

query = select(c for c in Contact if c.person.name.startswith('M')) 
for c in query: 
    print(c.person.name, c.type, c.value) 

、あなたは連絡先から人へのトラバース属性を実行するという理由だけで。

関連する問題