Как сделать так, чтобы столбец таблицы базы данных можно было обновить только одним способом?

Я использую Ruby on Rails v3.2.2 и хотел бы «защитить» атрибут класса/экземпляра, чтобы значение столбца таблицы базы данных можно было обновить только одним способом. То есть, например, если у меня есть две таблицы базы данных:

table1
- full_name_column

table2
- name_column
- surname_column

и я управляю table1 так, чтобы full_name_column обновлялся с помощью обратного вызова, указанного в соответствующем классе/модели table2, я хотел бы убедиться, что можно обновить значение full_name_column только с помощью этого обратного вызова .

Другими словами, я должен убедиться, что значение table2.full_name_column всегда

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

и что это не может быть другое значение. Так, например, если я попытаюсь "напрямую" обновить table1.full_name_column, это должно вызвать что-то вроде ошибки. Конечно, это значение должно быть читаемым.

Возможно ли это? Что вы посоветуете, как справиться с этой ситуацией?


Причины такого подхода...

Я хочу использовать этот подход, потому что я планирую выполнять поиск в базе данных по столбцам table1, где table1 содержит другие значения, связанные с объектом "профиль"/"человек"... в противном случае, возможно, мне придется сделать какой-то хак (может быть, сложный hack), чтобы направить эти поиски на table2, чтобы искать "#{table1.name_column} #{table1.surname_column}" строк.

Итак, я думаю, что простым способом является денормализация данных, как описано выше, но для этого требуется реализовать "необычный" способ обработки этих данных.

Кстати: ответ должен быть направлен на «решение» связанных процессов или поиск лучшего подхода к более эффективному управлению функциями поиска.


person Backo    schedule 27.04.2012    source источник


Ответы (2)


Реплицируя данные из таблицы 2 в таблицу 1, вы уже денормализовали их. Как и при любой денормализации, вы должны дисциплинированно поддерживать синхронизацию. Это означает, что вы не должны обновлять то, что вам не положено.

Хотя с помощью attr_accessible можно отгородиться от чего-либо, чтобы предотвратить случайное присвоение, способ работы Ruby означает, что нет способа гарантировать, что значение никогда не будет изменено. Если кто-то достаточно решителен, он найдет способ. Вот где дисциплина приходит.

Лучший подход — задокументировать, что столбец не следует изменять напрямую, заблокировать массовое назначение с помощью attr_accessible и оставить все как есть. На самом деле, насколько мне известно, не существует понятия атрибута, защищенного от записи.

person tadman    schedule 27.04.2012
comment
Как и вы в основном, еще один ваш хороший ответ. В любом случае, я подожду еще немного, чтобы узнать, есть ли у кого-то другое мнение. - person Backo; 27.04.2012

Вот два подхода для хранения данных на уровне базы данных...

Представления и материализованные таблицы.

Если возможно, таблица1 может быть VIEW или, например, MATERIALIZED QUERY TABLE (MQT). Терминология может немного отличаться, в зависимости от используемой RDMS, я думаю, что Oracle имеет МАТЕРИАЛИЗОВАННЫЕ ПРЕДСТАВЛЕНИЯ, тогда как DB2 имеет МАТЕРИАЛИЗОВАННЫЕ ТАБЛИЦЫ ЗАПРОСОВ.

VIEW — это просто доступ к данным, которые физически находятся в какой-то другой таблице. Где MATERIALIZED VIEW/QUERY TABLE является физической копией данных и поэтому, например, не синхронизируется с исходными данными в режиме реального времени.

Так или иначе. эти подходы обеспечивают доступ только для чтения к данным, которые принадлежат table2, но доступны для table1.

Пример очень простого представления:

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

Триггеры

Иногда представления неудобны, поскольку вам может понадобиться иметь некоторые данные в таблице 1, недоступные из других источников. В этих случаях вы можете рассмотреть возможность использования триггеров базы данных. т.е. создать триггер, который при обновлении таблицы 2 также обновляет таблицу 1 в рамках той же транзакции базы данных.

С триггерами проблема может заключаться в том, что вам нужно предоставить клиенту привилегии также обновлять таблицу1. Некоторые RDMS могут предоставлять некоторые способы настройки управления доступом к триггерам, то есть операции, выполняемые 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;
person Toni    schedule 27.04.2012
comment
Хорошо! Тем не менее, это слишком много усилий для того, что мне нужно сделать. Спасибо, в любом случае. - person Backo; 29.04.2012
comment
Все дело в том, чтобы решить, на каком уровне вы хотите хранить данные, и придерживаться его. Если у вас есть строгий контроль над кодом приложения, которое обращается к данным, то может быть проще применить там ограничения и репликацию данных. OTOH, если у вас есть несколько приложений и если вы хотите сделать их абстрактными, вам следует подумать о сохранении данных на уровне базы данных. - person Toni; 29.04.2012