关联操作发出关于合并相同列上的条件不再维护两个条件的弃用警告。

huangapple go评论68阅读模式
英文:

Association gives deprecation warning about merging conditions on the same column no longer maintain both conditions

问题

从Rails 6.0迁移到6.1时,遇到了这个弃用警告 when is called 'type_documents relation',:

ActionView::Template::Error (DEPRECATION WARNING: Merging ("documents"."type" IN ($1, $2, $3)) and (("documents"."type" = $1 OR "documents"."type" IN ($2, $3) AND "documents"."case_attachment_flag" = $4)) no longer maintain both conditions, and will be replaced by the latter in Rails 6.2. To migrate to Rails 6.2's behavior, use `relation.merge(other, rewhere: true)`.

我有这个关系:

has_many :type_documents,
             lambda {
               where(type: 'Document::Type')
                 .or(
                   where(
                     type: ['Document::Some1', 'Document::Some2'],
                     case_attachment_flag: true
                   )
                 )
             },
             dependent: :destroy,
             as: :record,
             class_name: 'Document::Type';

从6.0开始,SQL看起来像这样:

Document::Type Load (17.4ms)  SELECT "documents".* FROM "documents" WHERE "documents"."type" IN ($1, $2, $3) AND "documents"."record_id" = $4 AND "documents"."record_type" = $5 AND ("documents"."type" = $6 OR "documents"."type" IN ($7, $8) AND "documents"."case_attachment_flag" = $9)

发现这两个部分引发了警告:

where(type: 'Document::Type')

.or(
  where(
    type: ['Document::Some1', 'Document::Some2'],
    case_attachment_flag: true
  )
)

并且无法弄清楚如何在不使用SQL的情况下重写它。

注意:'type_documents'类似于文档部分,在视图中显示具有以下类型之一的文档的数据库中,'type'列应为'Document::Type'或'Document::Some1'和'Document::Some2',最后两者还应进行布尔标志检查。所有条件都来自同一表。

英文:

Migrated from Rails 6.0 to 6.1 and stumbled upon this deprecation when is called 'type_documents relation', :

ActionView::Template::Error (DEPRECATION WARNING: Merging ("documents"."type" IN ($1, $2, $3)) and (("documents"."type" = $1 OR "documents"."type" IN ($2, $3) AND "documents"."case_attachment_flag" = $4)) no longer maintain both conditions, and will be replaced by the latter in Rails 6.2. To migrate to Rails 6.2's behavior, use `relation.merge(other, rewhere: true)`. 

I have this relation:

has_many :type_documents,
             lambda {
               where(type: 'Document::Type')
                 .or(
                   where(
                     type: ['Document::Some1', 'Document::Some2'],
                     case_attachment_flag: true
                   )
                 )
             },
             dependent: :destroy,
             as: :record,
             class_name: 'Document::Type'

From 6.0, sql looks like:

Document::Type Load (17.4ms)  SELECT "documents".* FROM "documents" WHERE "documents"."type" IN ($1, $2, $3) AND "documents"."record_id" = $4 AND "documents"."record_type" = $5 AND ("documents"."type" = $6 OR "documents"."type" IN ($7, $8) AND "documents"."case_attachment_flag" = $9)

Found out, that these 2 parts are giving complain:

where(type: 'Document::Type')

and

.or(
  where(
    type: ['Document::Some1', 'Document::Some2'],
    case_attachment_flag: true
  )
)

And can't figure out how to rewrite it without using SQL.

Note: 'type_documents' is like document section, where are shown documents in view if in db under column 'type' document has one of these types: 'Document::Type' or 'Document::Some1' and 'Document::Some2', also last two should have that boolean flag check.
All conditions are from the same table.

答案1

得分: 3

也许你只是误解了警告的含义:

DEPRECATION WARNING: 合并 ("documents"."type" IN ($1, $2, $3)) 和 (("documents"."type" = $1 OR "documents"."type" IN ($2, $3) AND "documents"."case_attachment_flag" = $4)) 不再同时满足两个条件,并将在 Rails 6.2 中由后者替代。要迁移到 Rails 6.2 的行为,使用 `relation.merge(other, rewhere: true)。

实际上,这是在说查询可以简化,而 Rails 将在将来(或者如果您选择的话,现在就会这样做)为您完成这项工作。这并不保证简化后的结果将是所期望的,因为 Rails 只会假设第二个条件是预期的条件,这是根据警告来看的。

当前查询是:

"documents"."record_id" = $4` AND `"documents"."record_type" = $5

(这些是正常的)

然后您还有这个条件

"documents"."type" IN ($1, $2, $3)

这个条件实际上没有任何影响(除了使查询效率降低),因为 "documents.type" 已经受到进一步的限制:

("documents"."type" = $6 OR 
"documents"."type" IN ($7, $8) 
AND "documents"."case_attachment_flag" = $9)

这意味着:

  • "documents.type" 必须等于 $6(条件 1);或者
  • 它必须在列表 ($7, $8) 中,并且具有与 $9 相等的 case_attachment_flag(条件 2)

因此,如您所见,它是否在类型 ($1, $2, $3) 中并不重要,因为它必须通过上述两个测试中的一个。

Rails 已经识别到了[可能]矛盾的条件,并现在告诉您,将来将放弃第一个条件,采用第二个条件。

英文:

Maybe you are just misunderstanding what the warning is telling you:

> DEPRECATION WARNING: Merging ("documents"."type" IN ($1, $2, $3)) and (("documents"."type" = $1 OR "documents"."type" IN ($2, $3) AND "documents"."case_attachment_flag" = $4)) no longer maintain both conditions, and will be replaced by the latter in Rails 6.2. To migrate to Rails 6.2's behavior, use `relation.merge(other, rewhere: true)

What this is actually saying is that the query can be simplified and rails will be doing that for you in the future (or now if you opt in). This does not guarantee the simplification will be the desired result as Rails will, it appears based on the warning, just assume the second condition is the intended condition.

Right now the query is:

"documents"."record_id" = $4` AND `"documents"."record_type" = $5

(these are fine)

Then you also have this condition

"documents"."type" IN ($1, $2, $3)`

This condition has no impact whatsoever (other than making the query less efficient) because "documents.type" is already further constrained by:

("documents"."type" = $6 OR 
"documents"."type" IN ($7, $8) 
AND "documents"."case_attachment_flag" = $9)

This means that:

  • the documents.type must be equal to $6 (condition 1); OR
  • it must be in the list of ($7, $8) AND have a case_attachment_flag equal to $9 (condition 2)

So as you can see whether or not it is in types ($1, $2, $3) does not matter it because it must pass 1 of the 2 tests above.

Rails has recognized the [possibly] contradictory conditions and is now telling you it will forfeit the first for the second going forward.

答案2

得分: 0

解决方法是将以下部分更改为:

class_name: 'Document::Typed' 改为 class_name: 'Document::Base'

然后SQL查询会按照以下范围定义:

"documents"."type" = $1 OR "documents"."type" IN ($2, $3) AND "documents"."case_attachment_flag" = $4
英文:

Solution was to change:

class_name: 'Document::Typed' to class_name: 'Document::Base'

then sql was what is defined in scope:

"documents"."type" = $1 OR "documents"."type" IN ($2, $3) AND "documents"."case_attachment_flag" = $4

huangapple
  • 本文由 发表于 2023年2月24日 00:55:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/75547938.html
  • ruby-on-rails
  • ruby-on-rails-6.1