【发布时间】:2017-08-05 08:46:09
【问题描述】:
我正在尝试为我的 EventsLog 模型创建一个范围,该模型看起来类似于 EventsLog.with_values({"value_name" => "value", "other_value_name" => "other_value"})。
其结果将是 EventsLog 记录,这些记录对于散列中的每个键值对都具有关联的 EventsLogValue。
这是我必须处理的。 两个表的定义如下:
--table for tracking events
CREATE TABLE events_log(
id INT PRIMARY KEY IDENTITY(1,1),
event_name VARCHAR(25), --name of the event
created_at DATETIME
);
--table for tracking the values corresponding to the event
CREATE TABLE events_log_values(
id INT PRIMARY KEY IDENTITY(1,1),
event_id INT,
value VARCHAR(255),
value_name VARCHAR(25),
);
从这两个表中,两个模型看起来像:
class EventsLog < BaseAPIDatabase
self.table_name = "events_log"
self.primary_key = "id"
has_many :events_log_values, :foreign_key => "event_id", :primary_key => "id", :class_name => "EventsLogValue", :autosave => true
scope :since, ->(since){ where("created_at > ?", since)}
scope :named, ->(event_name){ where(:event_name => event_name) }
def values
events_log_values.inject({}) do |hsh, v|
hsh.merge({v.value_name => v.value})
end
end
end
class EventsLogValue < BaseAPIDatabase
self.table_name = "events_log_values"
self.primary_key = "id"
end
到目前为止,我的方法是尝试创建一个函数,该函数返回一个活动记录关系,该关系一次应用一个键值对,然后添加一个范围(或者可能只是一个返回关系的类方法)它为我链接它们(类似于scope :with_values, ->(values){values.inject(self){|slf, (k, v)| slf.with_value(k, v)} })。
最初我尝试将 with_value 实现为一个相当标准的范围 scope :with_value, ->(val_name, val){ eager_load(:events_log_values).where(:events_log_values => {:value_name => val_name, :value => val}) },它本身可以正常工作,但是当链接时会导致单个连接在连接值上有多个条件。
决定通过将值表与每个条件的别名连接来解决此问题;我的新方法是在我的 with_value 函数中定义一个 has_many 关联,然后为 eager_load 该关联添加一个基于每个新关联的 where 条件:
def self.with_value(val_name, val)
has_many val_name.to_sym, ->(){ where(:value_name => val_name) }, :foreign_key => "event_id", :primary_key => "id", :class_name => "EventsLogValue"
res = eager_load(:events_log_values)
res.eager_load(val_name.to_sym).where("#{val_name.pluralize}_events_log" => {:value => val})
end
这实际上工作得很好,但有一些问题。第一个是我很难知道在 where 条件下该协会的名称是什么。第二个(也是更大的问题)是我的 values 函数现在只有任何 value_names 没有为它们建立关联。
这是由多个 has_manys 生成的一些 sql,可能有助于说明我正在尝试做的事情:
EventsLog.with_values("hello" => "world", "foo" => "bar").to_sql
SELECT ...
FROM [events_log]
LEFT OUTER JOIN [events_log_values] ON [events_log_values].[event_id] = [events_log].[id]
LEFT OUTER JOIN [events_log_values] [hellos_events_log] ON [hellos_events_log].[event_id] = [events_log].[id] AND [hellos_events_log].[value_name] = 'hello'
LEFT OUTER JOIN [events_log_values] [foos_events_log] ON [foos_events_log].[event_id] = [events_log].[id] AND [foos_events_log].[value_name] = 'foo'
WHERE [hellos_events_log].[value] = 'world' AND [foos_events_log].[value] = 'bar'
我怎样才能得到一个记录,它有几个相关的记录满足几个不同的条件?
【问题讨论】:
标签: ruby-on-rails activerecord