今日、彼は自分のブログのモデルに携わり、エントリーにコメントカウンターを付けることにしました(これはブログエントリーです)。 アプリケーションのデータ表現は
SQLAlchemyを使用して実装されます。これは、データソースレイヤーの現在の(主にDjangoとRailsによる)
Active Record実装とは異なり、これが
データマッパー実装であることを思い出します。
コメントを数えるために、entries_tableにバッテリーがないため、毎回コメントを数える必要があります。 しかし、それを正しく行う方法は?
オンデマンドでダウンロード
最初に思い浮かぶのは、Entry.comments_count属性をオンデマンドでダウンロード可能(遅延読み込み属性)にし、リクエストを切断することです:
SELECT COUNT(*) FROM comments_table WHERE comments_table.entry_id == <ENTRY_ID>
それは簡単です、属性に頼る-要求が発生し、適用しない-それはしません。 しかし、たとえば、ブログのメインページでどのようにアピールが行われたか(各エントリのコメントの数が示されている)など、アピールがあまりにも頻繁に発生した場合はどうでしょう。 これには、n + 1クエリが必要になります。nはページごとのレコード数です。 あまり良くない...
テーブルを結合する
そして今、最も興味深いのは、SQLAlchemyがクラスを個々のテーブルだけでなく、JOINやSELECTにもマップできることです。 つまり、必要なのはSQLクエリを作成することだけです。
SELECT < entries_table>, COUNT(comments_table.id)
FROM entries_table
LEFT OUTER JOIN comments_table
ON entries_table.id == comments_table.entry_id
GROUP BY entries_table.id
SQLAlchemy
メタデータマッピングの説明を使用すると、次のようになります。
entries_with_comments = select(
[
entries_table,
func.count(comments_table.c.id).label("comments_count")
],
from_obj=[entries_table.outerjoin(comments_table)],
group_by=[c for c in entries_table.c]
).alias("entries_with_comments")
とても簡単です。 次に、古典的なエントリをこのSELECTにマップします::
mapper(Entry, schema.entries_with_comments,
primary_key=[schema.entries_with_comments.c.id],
)
すべて準備完了です! エントリエントリを取得すると、各インスタンスにcomments_count属性が設定されます。 そして、これらすべてを1つのリクエストで。
ActiveRecordを使用したDjango.ormとRailsは神経質になります;)。