0

Rails有许多可用的 ActiveRecord 版本控制 gem,但大多数(如果不是全部)都难以 维护。最重要的是,其中一些似乎有各种关联问题

我正在编写一个内容管理系统,其中页面存储在树状层次结构中,页面字段使用EAV 模型存储在单独的表中。

记住这一点,我并不是在寻找一个包罗万象的修订版宝石,因为老实说,我不认为我会找到一个。我正在寻找的是有关如何将其作为自定义实现来处理的一些建议。我应该有一个单独的表来存储修订并在我的 EAV 表中引用修订号吗?我预见这可能会导致一些复杂的验证问题。无论如何,我目前在寻找一种干净的方法来验证常规 EAV 表时遇到问题,因此,如果有人可以对此发表评论,我将不胜感激。

我希望这个问题写得足够好,符合 SO 标准。如果您需要任何其他信息,请随时询问,我会尽力帮助您。:)

4

1 回答 1

2

无论如何,我目前在寻找一种干净的方法来验证常规 EAV 表时遇到问题,因此,如果有人可以对此发表评论,我将不胜感激。

没有一种干净的方法来验证或约束 EAV 表。这就是 DBA 将其称为反模式的原因。(EAV 从幻灯片 16 开始。)Bill 没有谈论版本,所以我会。

版本控制看起来很简单,但事实并非如此。要对行进行版本化,您可以添加一列。它是版本号还是时间戳并不重要。

create table test (
  test_id integer not null,
  attr_ts timestamp not null default current_timestamp,
  attr_name varchar(35) not null,
  attr_value varchar(35) not null,
  primary key (test_id, attr_ts, attr_name)
);

insert into test (test_id, attr_name, attr_value) values
(1, 'emp_id', 1),
(1, 'emp_name', 'Alomar, Anton');

select * from test;

test_id  attr_ts                      attr_name   attr_value
--
1        2012-10-28 21:00:59.688436   emp_id      1
1        2012-10-28 21:00:59.688436   emp_name    Alomar, Anton

尽管它在输出时可能看起来不像,但所有这些属性值都是 varchar(35)。dbms 没有简单的方法来阻止某人输入 'wibble' 作为 emp_id。如果您需要类型检查,则必须在应用程序代码中进行。(而且您必须防止睡眠不足的 DBA 使用 dbms 提供的命令行和 GUI 界面。)

当然,对于规范化表,您只需将 emp_id 声明为整数类型。

使用版本控制,更新 Anton 的名字就变成了插入。

insert into test (test_id, attr_name, attr_value) values
(1, 'emp_name', 'Alomar, Antonio');

使用版本控制,选择有点复杂。您可以使用视图而不是公用表表达式。

with current_values as (
  select test_id, attr_name, max(attr_ts) cur_ver_ts
  from test
  -- You'll probably need an index on this pair of columns to get good performance.
  group by test_id, attr_name
)
select t.test_id, t.attr_name, t.attr_value
from test t
inner join current_values c 
        on c.test_id = t.test_id
       and c.attr_name = t.attr_name
       and c.cur_ver_ts = t.attr_ts

test_id   attr_name   attr_value
--
1         emp_id      1
1         emp_name    Alomar, Antonio

100 万行和 8 个不可为空的列的规范化表有 100 万行。一个类似的 EAV 表有 800 万行。一个版本化的 EAV 表有 800 万行,加上对每个值和每个属性名称的每次更改都有一行。

存储版本号并加入包含当前值的第二个表并不会获得太多收益(如果有的话)。每个(传统)插入都需要插入两个表。一行 8 列变成 16 行(两个表各有 8 个)。

选择稍微简单一些,只需要一个连接。

于 2012-10-29T01:41:17.837 回答