2

Problem と ProblemSet という 2 つの ActiveRecord モデルがあるとします。

@problem_set オブジェクトがあり、特定のタイトル属性に問題があるかどうかを確認したいとします。

あなたは言えた:

@problem_set.problems.where(:title => "Adding Numbers").any?

trueこれは、最適な SQL を実行してを返します。

SELECT COUNT(*) FROM "problems" INNER JOIN "problem_sets_problems" ON "problems"."id" = "problem_sets_problems"."problem_id" WHERE "problem_sets_problems"."problem_set_id" = 1 AND "problems"."title" = 'Adding Numbers'

ただし、@problem_set がメモリ内にある場合、つまり @problem_set を次のように取得した場合:

@problem_set = ProblemSet.new()
@problem_set.problems << Problem.new(:title = "Adding Numbers")

そうすると、問題を見つけることができなくなります (つまり、false が返されます!)。これは、次の SQL が実行されるためです。

SELECT COUNT(*) FROM "problems" INNER JOIN "problem_sets_problems" ON "problems"."id" = "problem_sets_problems"."problem_id" WHERE "problem_sets_problems"."problem_set_id" IS NULL AND "problems"."title" = 'Adding Numbers'

永続オブジェクトとメモリ内オブジェクトの両方に対してチェックを正しく実行する方法は次のとおりです。

@problem_set.problems.map(&:title).include? "Adding Numbers"

どちらの場合も正しく返さtrueれます。ただし、永続オブジェクトの場合は、最適化されていない SQL (すべての問題を取得します) を実行します。

SELECT "problems".* FROM "problems" INNER JOIN "problem_sets_problems" ON "problems"."id" = "problem_sets_problems"."problem_id" WHERE "problem_sets_problems"."problem_set_id" = 1

質問: 最適な SQL コードを実行しながら、同じコードを使用して永続オブジェクトとメモリ内オブジェクトの両方をチェックする方法はありますか?

オブジェクトの永続性をチェックするソリューションが許可されていることに注意してください (ただし、コレクションの汚れをチェックする方法はわかりません)。ただし、永続オブジェクトが変更された場合でも機能するはずです (つまり、関連付けコレクションの属性がダーティになり、SQL クエリの結果が古くなっている可能性があります)。

4

1 に答える 1

0

わかりました、私はついにそれを解決しました。

あいまいなレール機能をブラウズすると、persisted?メソッドが見つかりました。@problem_set.persisted?オブジェクトが永続的かインメモリのみかを確認するために使用できます。

したがって、答えは次のとおりです。

if @problem_set.persisted?
  @problem_set.problems.where(:title => "Adding Numbers").any?
else
  @problem_set.problems.map(&:title).include? "Adding Numbers"
end

残りの問題は、関連コレクションがダーティな永続オブジェクトはどうなるかということです。まあ、実験で、実際には起こらないことがわかりました。コレクションにオブジェクトを追加すると、たとえば次のいずれかになります。

@problem_set.problems << Problem.new(:title => "hello")
@problem_set.problems.push Problem.new(:title => "hello")

ActiveRecord はすぐにデータを保存します。同様に、次のように言うと、関連付けテーブルから行がすぐに破棄されます。

@problem_set.problems.delete(@problem_set.problems[2])

つまり、 のようなメソッドはありませんが、@problem_set.problems_changed?存在する場合、現在の実装ではproblems_changed?常に が返されfalseます。

実際には、、、collection<<メソッドは自動保存します (つまり、自動的に呼び出します)。collection.pushcollection.deletesave

于 2012-08-24T08:33:26.073 に答える