【问题标题】:How to make sure that it is possible to update a database table column only in one way?如何确保只能以一种方式更新数据库表列?
【发布时间】:2012-04-27 14:37:21
【问题描述】:

我正在使用 Ruby on Rails v3.2.2,我想“保护”一个类/实例属性,以便只能以一种方式更新数据库表列值。也就是说,例如,假设我有两个数据库表:

table1
- full_name_column

table2
- name_column
- surname_column

我管理table1,以便使用相关table2 类/模型中所述的回调更新full_name_column,我想确保可以更新full_name_column通过该回调。

换句话说,我应该确保 table2.full_name_column 值始终是

"#{table1.name_column} #{table1.surname_column}"

而且它不能是另一个值。因此,例如,如果我尝试“直接”更新table1.full_name_column,它应该会引发类似错误的信息。当然,该值必须是可读的。

有可能吗?您对处理这种情况有何建议?


采用这种方法的原因...

我想使用这种方法,因为我计划对 table1 列执行数据库搜索,其中 table1 包含与“profile”/“person”对象相关的其他值...否则,可能我必须进行一些 hack(可能是复杂的 hack)以将这些搜索定向到 table2,以便查找 "#{table1.name_column} #{table1.surname_column}" 字符串。

所以,我认为一种简单的方法是去规范化数据,如上所述,但它需要实现一种“不常见”的方法来处理该数据。 p>

顺便说一句:答案应该旨在“解决”相关流程或找到更好的方法来以更好的方式处理搜索功能。

【问题讨论】:

    标签: ruby-on-rails ruby database ruby-on-rails-3.2 denormalization


    【解决方案1】:

    这是在数据库级别维护数据的两种方法...

    视图和具体化表。

    如果可能,table1 可以是 VIEW 或例如 MATERIALIZED QUERY TABLE (MQT)。术语可能略有不同,具体取决于使用的 RDMS,我认为 Oracle 具有 MATERIALIZED VIEWs 而 DB2 具有 MATERIALIZED QUERY TABLEs。

    VIEW 只是对物理上位于某个不同表中的数据的访问。 MATERIALIZED VIEW/QUERY TABLE 是数据的物理副本,因此例如与源数据不实时同步。

    无论如何。这些方法将提供对数据的只读访问,这些数据由 table2 拥有,但可由 table1 访问。

    非常简单的视图示例:

    CREATE VIEW table1 AS 
       SELECT surname||', '||name AS full_name
         FROM table2;
    

    触发器

    有时视图并不方便,因为您实际上可能希望在 table1 中有一些其他地方无法获得的数据。在这些情况下,您可以考虑使用数据库触发器。 IE。创建触发器,当 table2 更新时,table1 也会在同一个数据库事务中更新。

    使用触发器的问题可能是您必须授予客户端更新 table1 的权限。一些 RDMS 可能会提供一些方法来调整触发器的访问控制,即 TRIGGER 执行的操作将使用与启动 TRIGGER 的操作不同的权限来执行。

    在这种情况下,TRIGGER 可能看起来像这样:

       CREATE TRIGGER UPDATE_NAME
         AFTER UPDATE OF NAME, SURNAME ON TABLE2
         REFERENCING NEW AS NEWNAME
         FOR EACH ROW
         BEGIN ATOMIC
           UPDATE TABLE1 SET FULL_NAME = NEWNAME.SURNAME||', '||NEWNAME.NAME
            WHERE SOME_KEY = NEWNAME.SOME_KEY
         END;
    

    【讨论】:

    • 好!但是,对于我需要做的事情来说,这太过分了。无论如何,谢谢。
    • 关键在于决定要维护数据的层级,并坚持下去。如果您对访问数据的应用程序代码有严格的控制,那么在那里实施限制和数据复制可能会更容易。 OTOH,如果您有多个应用程序,并且想要对它们进行抽象,您应该考虑在数据库层维护数据。
    【解决方案2】:

    通过将 table2 中的数据复制到 table1 中,您已经对其进行了反规范化。与任何反规范化一样,您必须遵守保持同步的原则。这意味着不要更新你不应该更新的东西。

    尽管您可以使用attr_accessible 隔离事物以防止意外分配,但 Ruby 的工作方式意味着无法保证该值永远不会被修改。如果有人有足够的决心,他们就会找到方法。这就是纪律的用武之地。

    最好的方法是记录不应该直接修改该列,使用attr_accessible 阻止批量分配,然后将其保留。据我所知,确实没有写保护属性的概念。

    【讨论】:

    • 正如您通常所做的那样,另一个您的好答案。反正我再等一会儿看看有没有其他人有不同意见。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-04
    相关资源
    最近更新 更多