说我有一个具有Foo和许多酒吧模型项目。
Foo和酒吧可以使物品可以被搜索,像这样搜索项目时,并作为参数:
www.example.com/search?foo=foovalue&bar[]=barvalue1&bar[]=barvalue2
我需要生成一个Query
对象,它是能够保存这些搜索参数。 我需要以下关系:
- 查询需要访问一个Foo和许多酒吧。
- 一个富可以通过许多不同的查询访问。
- 一个酒吧可以通过许多不同的查询访问。
- 无论是酒吧还是美孚需要了解任何查询。
我有这样的关系设置目前像这样:
class Query < ActiveRecord::Base
belongs_to :foo
has_and_belongs_to_many :bars
...
end
查询也有它返回一个像这样的哈希值的方法: { foo: 'foovalue', bars: [ 'barvalue1', 'barvalue2' }
这很容易让我将这些值传递到URL助手和生成搜索查询。
这一切工作正常。
我的问题是,这是否是建立这种关系的最佳途径。 我没见过的单向HABTM关系的任何其他的例子,所以我想我可能是错在这里做什么。
这是HABTM的可接受的使用?
在功能上,是的,但语义没有。 在“一边倒”的方式使用HABTM会正是你想要的实现。 该名HABTM确实不幸影射的相互关系并不总是如此。 同样, belongs_to :foo
没有什么直观的感觉在这里。
不要在HABTM和其他协会的语义被抓到,而不是只考虑在您的ID需要以适当和有效的查询数据坐下。 请记住,效率的考虑首先应考虑为您的工作效率。
我冒昧地创造出比你的Foo和酒吧更具体的例子......说我们有一个引擎,可以让我们查询某些鸭子是否存在于一个给定的池塘,我们要跟踪这些查询。
可能性
您有存储在您的查询记录鸭子三种选择:
- 加入表
- 鸭ID的本地阵列
- 鸭ID的序列化的阵列
你自己回答了连接表的使用情况,如果这是真的,“既不[鸭]也不[池塘]需要了解什么查询”,用片面的协会应该使你没有问题。 所有你需要做的就是创建一个ducks_queries
表和ActiveRecord的将提供其余部分。 你甚至可以选择使用has_many :through
,如果你需要做任何幻想的关系。
有时阵列比使用表连接更加方便。 您可以将数据存储为一个序列化整数数组,并添加处理程序访问类似于以下数据:
class Query
serialize :duck_ids
def ducks
transaction do
Duck.where(id: duck_ids)
end
end
end
如果您在数据库中有本地阵列支持,您可以在数据库中执行从相同。 类似。
随着Postgres的原生阵列支持,你可以做一个查询,如下所示:
SELECT * FROM ducks WHERE id=ANY(
(SELECT duck_ids FROM queries WHERE id=1 LIMIT 1)::int[]
)
您可以在上面的例子中发挥SQL小提琴
权衡
- 加入表:
- 优点:约定优于配置; 你得到所有的Rails的东西(如
query.bars
, query.bars=
, query.bars.where()
开箱 - 缺点:你已经增加了复杂性,以你的数据层(即另一个表,更密集的查询); 没有什么直观的感觉
- 原生数组:
- 优点:语义美观大方; 你的所有DB的阵列相关的东西开箱; 潜在的更高性能
- 缺点:你必须推出自己的Ruby / SQL或使用ActiveRecord的扩展名,例如postgres_ext ; 而非dB无关; 再见Rails的东西
- 序列化数组:
- 优点:语义美观大方; DB无关
- 缺点:你必须推出自己的红宝石; 你会松动,使直接通过您的数据库特定查询的能力; 串行化是恶心; 再见Rails的东西
在一天结束的时候,您的使用情况下,使所有的差异。 这且不说,我会说,你应该用你的“一边倒” HABTM实现坚持:你会以其他方式失去了很多Rails的赐予的礼物。