inverse_of 是做啥的?它生成啥 SQL?

Posted

技术标签:

【中文标题】inverse_of 是做啥的?它生成啥 SQL?【英文标题】:What does inverse_of do? What SQL does it generate?inverse_of 是做什么的?它生成什么 SQL? 【发布时间】:2012-03-06 23:45:47 【问题描述】:

我正试图了解inverse_of,但我不明白。

生成的 sql 是什么样子的(如果有的话)?

如果与:has_many:belongs_to:has_many_and_belongs_to 一起使用,inverse_of 选项是否表现出相同的行为?

抱歉,这是一个如此基本的问题。

我看到了这个例子:

class Player < ActiveRecord::Base
  has_many :cards, :inverse_of => :player
end

class Card < ActiveRecord::Base
  belongs_to :player, :inverse_of => :cards
end

【问题讨论】:

【参考方案1】:

从the documentation 看来,:inverse_of 选项似乎是一种避免 SQL 查询的方法,而不是生成它们。这是对 ActiveRecord 使用已加载数据而不是通过关系再次获取数据的提示。

他们的例子:

class Dungeon < ActiveRecord::Base
  has_many :traps, :inverse_of => :dungeon
  has_one :evil_wizard, :inverse_of => :dungeon
end

class Trap < ActiveRecord::Base
  belongs_to :dungeon, :inverse_of => :traps
end

class EvilWizard < ActiveRecord::Base
  belongs_to :dungeon, :inverse_of => :evil_wizard
end

在这种情况下,调用 dungeon.traps.first.dungeon 应该返回原始的 dungeon 对象,而不是像默认情况下那样加载一个新对象。

【讨论】:

你是否理解文档中的注释:“对于belongs_to 关联has_many 反向关联被忽略。”。然而,文档使用了那个确切的例子。我在这里错过了什么? 这对我来说很奇怪,因为在我看来你总是希望默认这种行为,并且只需要在无法推断关联名称时使用 :inverse_of 。定义中的不一致也很麻烦,但它在某些情况下帮助了我。有什么理由我不应该把它贴在任何地方? @Ibrahim 看看这个,它是 23 天前合并的! github.com/rails/rails/pull/9522 忽略 belongs_to 关联的逆是有意义的,因为记录 A 的父记录的子记录不能保证是记录 A——它可能是记录 A 的兄弟。但是,记录 A 的子项保证是记录 A。 未来的读者可能会从这个blog...中获得帮助:D【参考方案2】:

我认为:inverse_of 在处理尚未持久化的关联时最有用。例如:

class Project < ActiveRecord::Base
  has_many :tasks, :inverse_of=>:project
end

class Task < ActiveRecord::Base
  belongs_to :project, :inverse_of=>:tasks
end

现在,在控制台中:

irb> p = Project.new
=> #<Project id: nil, name: nil, ...>
irb> t = p.tasks.build
=> #<Task id: nil, project_id: nil, ...>
irb> t.project
=> #<Project id: nil, name: nil, ...>

如果没有 :inverse_of 参数,t.project 将返回 nil,因为它会触发一个 sql 查询并且数据尚未存储。使用:inverse_of 参数,从内存中检索数据。

【讨论】:

我遇到了accepts_nested_attributes_for 的问题。默认情况下,仅显示现有关联对象的嵌套属性(编辑操作)。例如,如果您想创建一个包含 3 个关联对象的对象,您应该在模型中包含 Model.new(新操作)和 :inverse_of。 同意 Rails 4 及更高版本中的行为,但它在 v3 中工作得很好(除了一些后来的化身,虽然旧语法在 v3.2.13 中再次工作)。并注意在连接模型中,不能再验证 id 的存在 - 只有模型对象。似乎您可以在 v4“逻辑”中建立一个没有 id 的关联。 完全正确.. :inverse_of 为我解决了在同一表单中创建新的父实体和子实体时的问题。【参考方案3】:

在此 pr (https://github.com/rails/rails/pull/9522) 之后,大多数情况下不需要 inverse_of

Active Record 支持自动识别大多数与标准名称的关联。但是,Active Record 不会自动识别包含范围或以下任何选项的双向关联:

:通过 :foreign_key
class Author < ApplicationRecord
  has_many :books, inverse_of: 'writer'
end

class Book < ApplicationRecord
  belongs_to :writer, class_name: 'Author', foreign_key: 'author_id'
end

a = Author.first
b = a.books.first
a.first_name == b.writer.first_name # => true
a.first_name = 'David'
a.first_name == b.writer.first_name # => true

在上面的示例中,对同一对象的引用存储在变量a 和属性writer 中。

【讨论】:

我使用的是 Rails 5,无论你是否添加 inverse_ofa.first_name == b.author.first_name 的结果总是正确的。 @ArslanAli 感谢您的精彩评论,我更新了答案。【参考方案4】:

当我们有 2 个具有 has_many 和 belongs_to 关系的模型时,最好使用 inverse_of 通知 ActiveRecod 它们属于关联的同一侧。因此,如果从一侧触发查询,如果从相反方向触发,它将缓存并从缓存中提供服务。这提高了性能。从 Rails 4.1 开始,inverse_of 将自动设置,如果我们使用 foreign_key 或更改类名,我们需要显式设置。

有关详细信息和示例的最佳文章。

http://viget.com/extend/exploring-the-inverse-of-option-on-rails-model-associations

【讨论】:

【参考方案5】:

只是为每个人提供的更新 - 我们刚刚将 inverse_of 与我们的一个具有 has_many :through 关联的应用程序一起使用


它基本上使“子”对象可以使用“原点”对象

因此,如果您使用的是 Rails 的示例:

class Dungeon < ActiveRecord::Base
  has_many :traps, :inverse_of => :dungeon
  has_one :evil_wizard, :inverse_of => :dungeon
end

class Trap < ActiveRecord::Base
  belongs_to :dungeon, :inverse_of => :traps
  validates :id,
      :presence =>  :message => "Dungeon ID Required", :unless => :draft? 

  private
  def draft?
      self.dungeon.draft
  end 
end

class EvilWizard < ActiveRecord::Base
  belongs_to :dungeon, :inverse_of => :evil_wizard
end

使用:inverse_of 将允许您访问与其相反的数据对象,而无需执行任何进一步的 SQL 查询

【讨论】:

【参考方案6】:

看看这篇文章!!

http://gsusmonzon.blogspot.com.br/2011/09/rails-power-of-inverseof.html

【讨论】:

【参考方案7】:

如果您在两个模型(用户和角色)之间有 has_many_through 关系,并且想要针对不存在或无效的 validates_presence of :user_id, :role_id 条目验证连接模型分配,那么它很有用。您仍然可以生成一个用户 @user 及其关联 @user.role(params[:role_id]),这样保存用户就不会导致分配模型验证失败。

【讨论】:

【参考方案8】:

请看2两个有用的资源

https://www.viget.com/articles/exploring-the-inverse-of-option-on-rails-model-associations http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#module-ActiveRecord::Associations::ClassMethods-label-Bi-directional+associations

记住inverse_of的一些限制:

不适用于 :through 关联。

不适用于 :polymorphic 关联。

对于belongs_to 关联has_many 反向关联被忽略。

【讨论】:

以上是关于inverse_of 是做啥的?它生成啥 SQL?的主要内容,如果未能解决你的问题,请参考以下文章

Eclipse中的checkstyle是做啥的,啥时候需要用到?

SQL:主键和索引到底是做啥的?

sqlserver management studio是做啥的 跟sqlserver有啥区别啊

有啥作用?。和 ?? javascript中的操作符是做啥的? [复制]

脚本是啥意思,是做啥的啊?

JavaScript 与Java、Java applet都有啥区别?各是做啥的?