Xit*_*ing 5 ruby activerecord ruby-on-rails jsonserializer
所以,我有麻烦
\n\nPreloading instance dependent scopes are not supported.\nRun Code Online (Sandbox Code Playgroud)\n\n我有三个型号
\n\nPreloading instance dependent scopes are not supported.\nRun Code Online (Sandbox Code Playgroud)\n\nclass P < ApplicationRecord\n has_many :as\n has_many :cs\nend\nRun Code Online (Sandbox Code Playgroud)\n\nclass C < ApplicationRecord\n belongs_to :p\nend\nRun Code Online (Sandbox Code Playgroud)\n\n我有三个 fast_jsonapi 序列化器
\n\nclass A < ApplicationRecord\n belongs_to :p\n has_one :c, -> (a) { where(feature: a.feature) }, through: :p, source: :cs\nend\nRun Code Online (Sandbox Code Playgroud)\n\nclass PSerializer\n include FastJsonapi::ObjectSerializer\n has_many :as\nend\nRun Code Online (Sandbox Code Playgroud)\n\nclass CSerializer\n include FastJsonapi::ObjectSerializer\n belongs_to :p\nend\nRun Code Online (Sandbox Code Playgroud)\n\n还有这个种子文件
\n\nclass ASerializer\n include FastJsonapi::ObjectSerializer\n belongs_to :p\n has_one :c\nend\nRun Code Online (Sandbox Code Playgroud)\n\n我想用他的 A 和 A\xe2\x80\x99s C\xe2\x80\x99s\n渲染 P 但当我尝试这样做时
\n\nPSerializer.new(P.first, { include: [:as, :\'as.c\'] }).serialized_json\nRun Code Online (Sandbox Code Playgroud)\n\n我有
\n\n P Load (0.1ms) SELECT "ps".* FROM "ps" ORDER BY "ps"."id" ASC LIMIT ? [["LIMIT", 1]]\n (0.1ms) SELECT "as"."id" FROM "as" WHERE "as"."p_id" = ? [["p_id", 1]]\n A Load (0.1ms) SELECT "as".* FROM "as" WHERE "as"."p_id" = ? [["p_id", 1]]\n C Load (0.2ms) SELECT "cs".* FROM "cs" INNER JOIN "ps" ON "cs"."p_id" = "ps"."id" WHERE "ps"."id" = ? AND "cs"."feature" = ? LIMIT ? [["id", 1], ["feature", "feature-0"], ["LIMIT", 1]]\n C Load (0.1ms) SELECT "cs".* FROM "cs" INNER JOIN "ps" ON "cs"."p_id" = "ps"."id" WHERE "ps"."id" = ? AND "cs"."feature" = ? LIMIT ? [["id", 1], ["feature", "feature-1"], ["LIMIT", 1]]\n C Load (0.1ms) SELECT "cs".* FROM "cs" INNER JOIN "ps" ON "cs"."p_id" = "ps"."id" WHERE "ps"."id" = ? AND "cs"."feature" = ? LIMIT ? [["id", 1], ["feature", "feature-2"], ["LIMIT", 1]]\n C Load (0.1ms) SELECT "cs".* FROM "cs" INNER JOIN "ps" ON "cs"."p_id" = "ps"."id" WHERE "ps"."id" = ? AND "cs"."feature" = ? LIMIT ? [["id", 1], ["feature", "feature-3"], ["LIMIT", 1]]\nRun Code Online (Sandbox Code Playgroud)\n\n所以,看起来像 N + 1。但我知道我可以使用 include 来解决它。
\n\nPSerializer.new(P.includes({ as: :c }).first, { include: [:as, :\'as.c\'] }).serialized_json\nRun Code Online (Sandbox Code Playgroud)\n\n哎呀:
\n\nirb(main):010:0> PSerializer.new(P.includes({ as: :c }).first, { include: [:as, :\'as.c\'] }).serialized_json\n P Load (0.1ms) SELECT "ps".* FROM "ps" ORDER BY "ps"."id" ASC LIMIT ? [["LIMIT", 1]]\n A Load (0.1ms) SELECT "as".* FROM "as" WHERE "as"."p_id" = ? [["p_id", 1]]\nTraceback (most recent call last):\n 1: from (irb):10\nArgumentError (The association scope \'c\' is instance dependent (the scope block takes an argument). Preloading instance dependent scopes is not supported.)\nRun Code Online (Sandbox Code Playgroud)\n\n我可以尝试使用 left_joins
\n\nirb(main):011:0> PSerializer.new(P.left_joins({ as: :c }).first, { include: [:as, :\'as.c\'] }).serialized_json\nTraceback (most recent call last):\n 1: from (irb):11\nArgumentError (The association scope \'c\' is instance dependent (the scope block takes an argument). Preloading instance dependent scopes is not supported.)\nRun Code Online (Sandbox Code Playgroud)\n\n实际上是一样的。\n我该如何解决这个 N + 1 问题?
\n\n我用这些模型创建了 Rails 存储库,因此您可以自行尝试。\n https://github.com/X1ting/reproduct_preload_bug \nRails 5.2.3\nRuby 2.5.1
\n非常感谢@igor-khodyrev
他建议我使用复合键,效果很好!所以,解决方案:
将 gem 添加到 Gemfile
gem 'composite_primary_keys', '=11'
Run Code Online (Sandbox Code Playgroud)
并将 A 模型中的关联更改为此
has_one :c, foreign_key: [:p_id, :feature], primary_key: [:p_id, :feature]
Run Code Online (Sandbox Code Playgroud)
N+1 解决:
irb(main):005:0> PSerializer.new(P.includes({ as: :c }).first, { include: [:as, :'as.c'] }).serialized_json
P Load (0.2ms) SELECT "ps".* FROM "ps" ORDER BY "ps"."id" ASC LIMIT ? [["LIMIT", 1]]
A Load (0.1ms) SELECT "as".* FROM "as" WHERE "as"."p_id" = ? [["p_id", 1]]
C Load (0.1ms) SELECT "cs".* FROM "cs" WHERE ("cs"."p_id" = 1 AND "cs"."feature" = 'feature-0' OR "cs"."p_id" = 1 AND "cs"."feature" = 'feature-1' OR "cs"."p_id" = 1 AND "cs"."feature" = 'feature-2' OR "cs"."p_id" = 1 AND "cs"."feature" = 'feature-3' OR "cs"."p_id" = 1 AND "cs"."feature" = 'feature-kek')
=> "{\"data\":{\"id\":\"1\",\"type\":\"p\",\"relationships\":{\"as\":{\"data\":[{\"id\":\"1\",\"type\":\"a\"},{\"id\":\"2\",\"type\":\"a\"},{\"id\":\"3\",\"type\":\"a\"},{\"id\":\"4\",\"type\":\"a\"},{\"id\":\"5\",\"type\":\"a\"}]}}},\"included\":[{\"id\":\"1\",\"type\":\"a\",\"relationships\":{\"p\":{\"data\":{\"id\":\"1\",\"type\":\"p\"}},\"c\":{\"data\":{\"id\":\"1\",\"type\":\"c\"}}}},{\"id\":\"2\",\"type\":\"a\",\"relationships\":{\"p\":{\"data\":{\"id\":\"1\",\"type\":\"p\"}},\"c\":{\"data\":{\"id\":\"2\",\"type\":\"c\"}}}},{\"id\":\"3\",\"type\":\"a\",\"relationships\":{\"p\":{\"data\":{\"id\":\"1\",\"type\":\"p\"}},\"c\":{\"data\":{\"id\":\"3\",\"type\":\"c\"}}}},{\"id\":\"4\",\"type\":\"a\",\"relationships\":{\"p\":{\"data\":{\"id\":\"1\",\"type\":\"p\"}},\"c\":{\"data\":{\"id\":\"4\",\"type\":\"c\"}}}},{\"id\":\"5\",\"type\":\"a\",\"relationships\":{\"p\":{\"data\":{\"id\":\"1\",\"type\":\"p\"}},\"c\":{\"data\":null}}},{\"id\":\"1\",\"type\":\"c\",\"relationships\":{\"p\":{\"data\":{\"id\":\"1\",\"type\":\"p\"}}}},{\"id\":\"2\",\"type\":\"c\",\"relationships\":{\"p\":{\"data\":{\"id\":\"1\",\"type\":\"p\"}}}},{\"id\":\"3\",\"type\":\"c\",\"relationships\":{\"p\":{\"data\":{\"id\":\"1\",\"type\":\"p\"}}}},{\"id\":\"4\",\"type\":\"c\",\"relationships\":{\"p\":{\"data\":{\"id\":\"1\",\"type\":\"p\"}}}}]}"
Run Code Online (Sandbox Code Playgroud)
我还将解决方案 PR 添加到了我的存储库中。 https://github.com/X1ting/reproduct_preload_bug/pull/1
| 归档时间: |
|
| 查看次数: |
984 次 |
| 最近记录: |