25

私はこのようなスキーマを持っています。

データベース スキーマ

managers  
    has_many :emails  
    has_many :stores

emails  
    belongs_to :manager

stores  
    belongs_to :manager  
    belongs_to :region

regions  
    has_many :stores  
    has_many :readings

readings  
    belongs_to :regions

経営者の方に鑑定をお願いしたいです。SQLでは、私はこのようなことをします。

SELECT * FROM managers  
    JOIN stores ON stores.manager_id = managers.id  
    JOIN regions ON stores.region_id = regions.id  
    JOIN readings ON readings.region_number = regions.number  
WHERE  
    manager.name = 'John Smith'  
AND  
    regions.number = '1234567'
LIMIT 100

アクティブレコードでこれを行う方法がわかりません。私はhttp://guides.rubyonrails.org/active_record_querying.htmlhttp://guides.rubyonrails.org/association_basics.htmlを理解しようとしていますが、それは沈んでいません。別の視点。

私はこのようにデータにアクセスすると思っていましたが、それがどのように機能するのか理解していないと思います.

managers.name  
managers.stores.name  
managers.stores.regions.readings.limit(10)

私はずっと醜いこのようなことをしなければなりませんでした。

managers.first.stores.first.regions.first.readings.limit(10)
4

4 に答える 4

49

次のモデル (および has_many の使用) を検討してください。

class Reading < ActiveRecord::Base
  belongs_to :region,
    inverse_of: :readings
end

class Region < ActiveRecord::Base
  has_many :readings,
    inverse_of: :region

  has_many :stores,
    inverse_of: :region    
end

class Store < ActiveRecord::Base
  belongs_to :region,
    inverse_of: :stores

  belongs_to :manager,
    inverse_of: :stores
end

class Manager < ActiveRecord::Base
  has_many :stores,
    inverse_of: :region

  has_many :emails,
    inverse_of: :manager

  has_many :regions,
    through: :stores

  has_many :readings,
    through: :regions
end

class Email < ActiveRecord::Base
  belongs_to :manager,
    inverse_of: :emails
end

マネージャーの測定値を取得したいと言っていますが、SQL は測定値をまったく選択せず、地域も規定しているため、質問は少しあいまいです。

特定の Manager と Region に一致するすべての Reading が必要であると仮定します。

@readings = Reading.joins(region: { stores: :manager }).where(
  manager: { name: 'John Smith' },
  region: { id: 1234567 })

1+N クエリを回避するために、リージョン、ストア、およびマネージャーも積極的に読み込みたいと仮定します。

@readings = Reading.includes(region: { stores: :manager }).where(
  manager: { name: 'John Smith' },
  region: { id: 1234567 })

マネージャーの名前があり、その詳細と読み取り値の両方が必要であると仮定します。

@manager = Manager.where(name: 'John Smith').first!
@readings = manager.readings

上記のすべてのクエリ例は、さらに条件、または、、、などで連鎖ActiveRecord::Relationできる を返します。wherejoinslimitgrouphavingorder

joins、、、およびメソッドincludesの違いも考慮する必要がpreloadあります。Arel は結合とエイリアシングもサポートしているため、Arel に関するドキュメント、ガイド、ブログを読むことをお勧めしますeager_loadreferences

しばらくの間 ActiveRecord を使用した結果、Sequel/SequelModel は ActiveRecord よりもはるかに優れた DB/ORM であるという結論に達しました。開発者に無礼ではありませんが、Sequel の方が優れたツールであることがわかりました。Arel には何年も前からドキュメントが薄く、ActiveRecord/Arel には、結合条件、結合タイプの制御と熱心な読み込み、結合、交差、再帰クエリ、ツリー/隣接リスト、および Sequel が提供する他の多くの SQL 機能など、多くの分野で失敗があります。カバーします。

AR を使い始めたばかりのように見えるので、AR と Arel のバラバラな使用、関係と関連付け、クエリ構成の奇妙な点など、ActiveRecord クエリの弱点やフラストレーションに苦しむよりも、代わりに Sequel から始めたいと思うかもしれません。の上。必要なSQLを知ることほどイライラすることはありませんが、ActiveRecord/Arelが共謀してあなたを止めようとするので、宣伝されたエスケープルートを使用し、「SQL文字列フラグメントを使用するだけ」を余儀なくされ、連鎖できない結果が返されますですが、コードの残りの部分では Relation が必要です! (例: ページ化された結果)

于 2013-10-04T16:56:44.190 に答える
8

13 年 10 月 4 日 14:39 の user1757006からのコメントにコメントしたかったのですが、十分なポイントがありません..とにかく、これはより深いネストのシナリオに対応しています。追加のモデルをチェーンする必要がある場合に構文がどのように機能するかを示すために、惑星と国のモデルを追加しました。

@readings = Reading.includes(planet: [ country: [ region: [ {stores:
:manager}]]]).where(
manager: { name: 'John Smith' },   
region: {id: 1234567 })
于 2016-04-17T00:37:59.203 に答える
5

このようなことを試してください:

managers.joins(stores: {regions: :readings}).where('managers.name = ? AND regions.number = ?', 'John Smith', '1234567').limit(100) 
于 2013-10-04T07:17:33.627 に答える