Rails自引用层次关系 [英] Rails self-referential hierarchical relationship
问题描述
我已经阅读了Rails指南,并尝试了一些带有Active Record的东西,但是还没有弄清楚实现此目的的最佳方法是什么.
I've read Rails guides and tried a few different things w/Active Record but haven't been able to figure out what the best way to do this is.
我需要建立一个分层的自引用(用户到用户)关系.通常,它的高度不超过5个级别,但应该可以无限扩大.
I need to set up a self-referential (users to users) relationship that is hierarchical. It usually would be no more than 5 levels high, but should be able to scale up infinitely.
我尝试用这样的数据库模式创建UserHierarchy
模型:
I've tried creating a UserHierarchy
model with a DB schema like this:
parent | child | level
但是,管理起来有点困难,太复杂了.
However, managing this is a bit too difficult and too complicated to handle.
在Rails中建立自引用层次关系的最佳方法是什么?我已经检查了祖先之类的宝石,但是其中大多数使用类继承,并且对于自引用关系而言效果不佳.这是一个多对多的自引用层次结构(在MySQL中).
What's the best way in Rails to do a self-referential hierarchical relationship? I've checked out gems like ancestry, but the majority of them use class inheritance and don't work well for self-referential relationships. It's a many-to-many, self-referential hierarchy (in MySQL).
推荐答案
祖先是esp的瑰宝之一.非常适合对象树结构(您称为自引用层次关系).您应该对此有更详细的了解.
Ancestry is one of the gems that is esp. well suited for object tree structures (what you call self-referential hierarchical relationships). You should have a more detailed look at it.
通常,有大约四种常见的方式将树存储在SQL数据库中:
Generally, there are about four common ways to store trees in a SQL database:
- 简单的父指针.您只需向模型中添加一个名为
parent_id
的新列,即可保存父对象的ID.这样可以轻松插入,并且非常适合单级层次结构,但是通常很难用于更深层次的层次结构,因此通常不用作主要机制(尽管有时会与其他机制结合使用) - 嵌套集.您将树定义为结构套套.通常使用
right
和left
列来实现,这些列填充有数字以定义集合.它允许有效的查询,但是在插入值时有些棘手. Esp.当同时对树进行更改时,有时会出现不一致的情况.该模型例如习惯了 awesome_nested_set 宝石. - 材料化路径.这是模型,例如由祖先使用.它存储所有元素的完整父路径.这允许有效的插入和查询.换一棵树要贵一些.
- 关闭树 .此机制将每个元素的所有父元素存储在一个表中.这是例如由 closure_tree 宝石使用.
- Simple parent pointers. You just add a new column called
parent_id
to your model holding the ID of the parent object. This allows easy inserts and is well suited for single-level hierarchies but is generally difficult to use for deeper hierarchies and is thus generally not used as the primary mechanism (although it is sometimes combined with other mechanisms) - Nested Sets. You define your trees as a structure of nested sets. This is typically implemented with a
right
and aleft
column which are populated with numbers to define the set. It allows efficient querying but is a bit tricky when inserting values. Esp. when having concurrent changes to a tree, it is sometimes prone to inconsistencies. This model is e.g. used to the awesome_nested_set gem. - Materialized Paths. This is the model e.g. used by ancestry. It stores the full parent path of all elements. This allows for efficient inserting and querying. Changing a tree is bit more expensive.
- Closure Trees. This mechanism stores for each element all of its parents in a table. This is e.g. used by the closure_tree gem.
通常,所有这些选项都允许存储对象树,即同一类对象的分层结构(在这种情况下为ActiveRecord
模型).
Generally, all these options allow to store a tree of objects, i.e. a hierarchical structure of objects of the same class (an ActiveRecord
model in this case).
使用哪种取决于特定的使用案例,哪些折衷方案更为重要.最重要的是,您应该弄清楚您是否经常更改树(例如,移动子树或仅添加叶子)以及如何查询树(例如,您是否仅需要直子,是否需要整个子树,您需要进行过滤),然后基于此选择合适的解决方案.
Which one to use depends on which trade-offs are more important for your specific use-case. Most importantly, you should figure out if you are changing trees often (e.g. moving sub-trees around or adding only leaves) and how you are querying the tree (e.g. do you only need direct children, do you need whole sub-trees, do you need to filter) and chose the appropriate solution based on that.
这篇关于Rails自引用层次关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!