78

私は PHP 開発者で、Ruby on Rails の素晴らしさを学んでいます。私は ActiveRecord が大好きで、非常に興味深いことに気付きました。これは、ActiveRecord メソッドがメソッド チェーンの終わりを検出してクエリを実行する方法です。

@person = Person.where(name: 'Jason').where(age: 26)

# In my humble imagination I'd think that each where() executes a database query
# But in reality, it doesn't until the last method in the chain

この魔術はどのように機能しますか?

4

4 に答える 4

166

このwhereメソッドはActiveRecord::Relationオブジェクトを返しますが、このオブジェクト自体はデータベース クエリを発行しません。重要なのは、このオブジェクトをどこで使用するかです。

コンソールでは、おそらくこれを行っています。

@person = Person.where(name: "Jason")

そして、データベースクエリを発行し、Jason という名前の全員の配列のように見えるものを返します。よし、アクティブレコード!

しかし、あなたは次のようなことをします:

@person = Person.where(name: "Jason").where(age: 26)

そして、それは別のクエリを発行しますが、これは 26 歳のジェイソンと呼ばれる人々のためのものです。しかし、それは1 つのクエリしか発行していません。


他の人が示唆しているように、これはwhereメソッドがプロキシ オブジェクトを返すために発生しています。要求されない限り、実際にクエリを実行してデータセットを返すことはありません。

コンソールで何かを実行すると、実行した結果の検査済みバージョンが出力されます。コンソールに入れ1てEnterキーを押すと、 is であるため元に1戻ります。魔法!についても同様です。他のさまざまなオブジェクトにはメソッドが定義されていないため、Ruby は のような恐ろしいものを返すオブジェクトにフォールバックます。1.inspect1"1"inspectObject<Object#23adbf42560>

すべてのActiveRecord::Relationオブジェクトにはinspectメソッドが定義されているため、クエリが発生します。コンソールでクエリを作成すると、IRB はinspectそのクエリからの戻り値を呼び出し、表示される配列のように、ほとんど人間が判読できるものを出力します。


これを標準の Ruby スクリプトで発行しただけの場合、オブジェクトが ( 経由でinspect) 検査されるか、 を使用して反復されるeachか、to_aメソッドが呼び出されるまで、クエリは実行されません。

whereこれら 3 つのいずれかが発生するまでは、好きなだけステートメントを連鎖させることができますinspect。その後、to_aまたはを呼び出すと、each最終的にそのクエリが実行されます。

于 2012-05-25T02:21:25.127 に答える
8

データベースへのクエリを実際に起動する「キッカー」と呼ばれるメソッドがいくつかあります。その前に、AST ノードを作成するだけで、キックされると実際の SQL (またはコンパイル対象の言語) が生成され、クエリが実行されます。

これがどのように行われるかの詳細な説明については、このブログ投稿を参照してください。

于 2012-05-25T00:49:54.707 に答える
4

コードを読むことができますが、ここでの 1 つの概念はプロキシ パターンです。

おそらく @person は実際のオブジェクトではなく、このオブジェクトのプロキシであり、属性が必要な場合は、アクティブなレコードが最終的にクエリを実行します。Hibernate にも同じ概念があります。

于 2012-05-25T00:48:41.377 に答える