模型布局
Article (has_many :attachments, :comments, :tags)
- id: string
Comment (has_many :attachments)
- id: integer
- article_id: string
Attachment
- id: integer
- reference_type: string
- reference_id: string
Tag
- id: integer
- article_id: string
错误查询
在 rails console
我运行:
Article.includes(:tags, :comments => :attachments).references(:tags)
由此产生的错误是:
Article.includes(:tags, :comments => :attachments).references(:tags)
SQL (0.7ms) SELECT "articles"."id" AS t0_r0, "articles"."created_at" AS t0_r1, "articles"."updated_at" AS t0_r2, "tags"."id" AS t1_r0, "tags"."article_id" AS t1_r1, "tags"."created_at" AS t1_r2, "tags"."updated_at" AS t1_r3, "comments"."id" AS t2_r0, "comments"."article_id" AS t2_r1, "comments"."created_at" AS t2_r2, "comments"."updated_at" AS t2_r3, "attachments"."id" AS t3_r0, "attachments"."reference_type" AS t3_r1, "attachments"."reference_id" AS t3_r2, "attachments"."created_at" AS t3_r3, "attachments"."updated_at" AS t3_r4 FROM "articles" LEFT OUTER JOIN "tags" ON "tags"."article_id" = "articles"."id" LEFT OUTER JOIN "comments" ON "comments"."article_id" = "articles"."id" LEFT OUTER JOIN "attachments" ON "attachments"."reference_id" = "comments"."id" AND "attachments"."reference_type" = $1 [["reference_type", "Comment"]]
ActiveRecord::StatementInvalid: PG::UndefinedFunction: ERROR: operator does not exist: character varying = integer
LINE 1: ...OIN "attachments" ON "attachments"."reference_id" = "comment_...
^
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
: SELECT "articles"."id" AS t0_r0, "articles"."created_at" AS t0_r1, "articles"."updated_at" AS t0_r2, "tags"."id" AS t1_r0, "tags"."article_id" AS t1_r1, "tags"."created_at" AS t1_r2, "tags"."updated_at" AS t1_r3, "comments"."id" AS t2_r0, "comments"."article_id" AS t2_r1, "comments"."created_at" AS t2_r2, "comments"."updated_at" AS t2_r3, "attachments"."id" AS t3_r0, "attachments"."reference_type" AS t3_r1, "attachments"."reference_id" AS t3_r2, "attachments"."created_at" AS t3_r3, "attachments"."updated_at" AS t3_r4 FROM "articles" LEFT OUTER JOIN "tags" ON "tags"."article_id" = "articles"."id" LEFT OUTER JOIN "comments" ON "comments"."article_id" = "articles"."id" LEFT OUTER JOIN "attachments" ON "attachments"."reference_id" = "comments"."id" AND "attachments"."reference_type" = $1
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activerecord-5.0.0/lib/active_record/connection_adapters/postgresql_adapter.rb:598:in `async_exec'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activerecord-5.0.0/lib/active_record/connection_adapters/postgresql_adapter.rb:598:in `block in exec_no_cache'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activerecord-5.0.0/lib/active_record/connection_adapters/abstract_adapter.rb:566:in `block in log'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activesupport-5.0.0/lib/active_support/notifications/instrumenter.rb:21:in `instrument'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activerecord-5.0.0/lib/active_record/connection_adapters/abstract_adapter.rb:560:in `log'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activerecord-5.0.0/lib/active_record/connection_adapters/postgresql_adapter.rb:598:in `exec_no_cache'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activerecord-5.0.0/lib/active_record/connection_adapters/postgresql_adapter.rb:587:in `execute_and_clear'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activerecord-5.0.0/lib/active_record/connection_adapters/postgresql/database_statements.rb:103:in `exec_query'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activerecord-5.0.0/lib/active_record/connection_adapters/abstract/database_statements.rb:373:in `select'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activerecord-5.0.0/lib/active_record/connection_adapters/abstract/database_statements.rb:41:in `select_all'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activerecord-5.0.0/lib/active_record/connection_adapters/abstract/query_cache.rb:70:in `select_all'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activerecord-5.0.0/lib/active_record/relation/finder_methods.rb:389:in `find_with_associations'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activerecord-5.0.0/lib/active_record/relation.rb:699:in `exec_queries'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activerecord-5.0.0/lib/active_record/relation.rb:580:in `load'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activerecord-5.0.0/lib/active_record/relation.rb:260:in `records'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activerecord-5.0.0/lib/active_record/relation.rb:683:in `inspect'
... 1 levels...
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/railties-5.0.0/lib/rails/commands/console_helper.rb:9:in `start'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/railties-5.0.0/lib/rails/commands/commands_tasks.rb:78:in `console'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/railties-5.0.0/lib/rails/commands/commands_tasks.rb:49:in `run_command!'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/railties-5.0.0/lib/rails/commands.rb:18:in `<top (required)>'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:293:in `require'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:293:in `block in require'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:259:in `load_dependency'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:293:in `require'
from /Users/jeremy/Documents/Synack/Code/experiments/joins-test/bin/rails:9:in `<top (required)>'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:287:in `load'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:287:in `block in load'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:259:in `load_dependency'
from /Users/jeremy/.rvm/gems/ruby-2.2.2@rails5/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:287:in `load'
from /Users/jeremy/.rvm/rubies/ruby-2.2.2/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'
from /Users/jeremy/.rvm/rubies/ruby-2.2.2/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'
查询成功
如果没有 .references()
子句,查询将正常工作,并分别获取所有模型,创建四个单独的请求。
在 rails console
我运行:
Article.includes(:tags, :comments => :attachments)
我明白了:
Article.includes(:tags, :comments => :attachments)
Article Load (5.1ms) SELECT "articles".* FROM "articles"
Tag Load (0.3ms) SELECT "tags".* FROM "tags" WHERE "tags"."article_id" = 'seedacorn-123'
Comment Load (0.2ms) SELECT "comments".* FROM "comments" WHERE "comments"."article_id" = 'seedacorn-123'
Attachment Load (0.3ms) SELECT "attachments".* FROM "attachments" WHERE "attachments"."reference_type" = $1 AND "attachments"."reference_id" IN ('1', '2') [["reference_type", "Comment"]]
=> #<ActiveRecord::Relation [#<article id: "seedacorn-123", created_at: "2016-07-15 22:41:27", updated_at: "2016-07-15 22:41:27">]>
问题
所以我想,我真正想知道的是,为什么 ActiveRecord 将 所有 包含的模型添加到 JOIN
而不仅仅是我添加到 .references()
?这是为了提高性能吗?还是出于其他原因需要这样做?
我没有将 :comments
或 :comments => :attachments
添加到 .references()
中,但它们仍然被添加到加入
。这会导致类型转换错误,但我想知道为什么一开始会发生这种情况?
问
如果您知道如何使用某种创造性的解决方案来解决这个问题,我正在拼命地尝试弄清楚。核心问题是我的多态 Attachment
模型可以使用 String 或 Integer 主键引用其他模型,因此它的 reference_type
是一个字符串。然后,在引入 JOIN
的情况下,查询其他模型时无法正确进行类型转换。
最佳答案
在 github.com/rail/rails 上发布问题后找到了此问题的答案.
事实证明,这是 Rails 中已知的(不幸的是预期的)行为。如果您需要使用单独的查询加载关联并且不作为JOIN
的一部分,您可以使用preload
而不是 includes
,它将始终在单独的查询中加载关联。
同样,如果你想强制加载一个关联作为 JOIN
的一部分,并且你没有使用 includes
,你可以替换 references
与 eager_load
。
所以
Article.includes(:tags, :comments => :attachments).references(:tags)
会变成
Article.preload(:tags, :comments => :attachments).eager_load(:tags)
关于ruby-on-rails - ActiveRecord `.references` 加入比必要更多的表? (并导致错误),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38406304/