假设您有两个 ActiveRecord 模型 - Problem 和 ProblemSet。
你有一个@problem_set 对象,你想检查它是否有某个标题属性的问题。
你可以说:
@problem_set.problems.where(:title => "Adding Numbers").any?
通过运行最佳 SQL返回true
:
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")
然后你将无法找到问题(即它返回错误!)。这是因为运行了以下 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 查询的结果将过期),它仍然可以工作。