【发布时间】:2011-11-23 02:57:42
【问题描述】:
如果您愿意,请提供一点帮助。
我想与我的“产品”类创建一个递归关系。我可以让一种产品成为其他产品的父产品。我的问题是如何在我的模型中创建这种关系?
这样合适吗?
has_many :products
belongs_to :product
【问题讨论】:
标签: ruby-on-rails-3 activerecord ruby-on-rails-3.1 associations
如果您愿意,请提供一点帮助。
我想与我的“产品”类创建一个递归关系。我可以让一种产品成为其他产品的父产品。我的问题是如何在我的模型中创建这种关系?
这样合适吗?
has_many :products
belongs_to :product
【问题讨论】:
标签: ruby-on-rails-3 activerecord ruby-on-rails-3.1 associations
逻辑上您提出的解决方案没有任何问题。但是,您可能需要执行以下操作:
belongs_to :parent, class_name: "Product", foreign_key: "parent_id"
has_many :children, class_name: "Product", foreign_key: "parent_id"
您基本上是在存储一棵“树”,顶部有一个产品,下面是子产品的分支,可能有很多层次。
您示例中的策略称为Adjacency List。很容易找到任何给定记录的直系父代和直系后代。但是,获取所有后代(包括后代的后代)可能会很困难,而且树越深越难。
另一种常用的方法是Nested Set,其中每条记录都将有关对象的信息存储在其“左侧”和“右侧”。这使您可以非常快速地(或至少有效地,在单个查询中)构建一棵树,无论它有多大。但是,它更复杂,插入记录通常意味着必须重新计算并更新插入记录右侧的所有记录。
第三种选择(可以说是一种中间立场)是使用Path Enumeration,其中对象将其整个路径存储在树中。所以,给定一棵这样的树:
A
/ \
B C
|
D
A 将具有空白路径(无父路径),B 和 C 将具有路径 A,D 将具有路径 A/C。使用此解决方案,大多数插入操作相对便宜,并且查询非常容易。然而,它仍然相当复杂,并且在树中移动对象可能会变得很昂贵。
还有其他选项,例如Closure Tables。
如果一个简单的邻接列表可以满足您的需求,那么就使用它。它绝对是最简单和最容易理解的。有一些 gem 实现了嵌套集合,也许还有其他一些树模式,所以如果你走这条路,你不必自己做所有繁重的工作。
【讨论】: