[Архитектура] Историчность справочников в системах оперативного учета
или я не очень понятно описал проблему?
![](/images/graemlins/smile.gif)
Если будешь делать хранения всей истории версий записей, то задумайся на тем, "чего хочет юзер", например, вот в такой ситуации (имхо, вполне вероятной):
Юзер-бухгалтер печатает накладную, видит в ней старый адрес, и понимает что он устарел. Тогда он идет в справочник контрагентов, меняет там адрес (тем самым создается новая версия записи в справочнике контрагентов а накладная-то уже сохранена со ссылкой на предыдущую версию записи клиента. И как теперь распечатать накладную с новым адресом?
записи разные, но объект один, ссылка должна быть на объект, а не на запись
И мой вопрос в том, как грамотно ( чтобы юзеру понятно было) эти случаи различать, в случае если у нас ведется история изменения записей?
А так же, это может быть не один документ, а например, пачка документов.
(Имхо, в идеале иметь такую структуру БД, в которой клиент - это одна сущность, а реквизиты клиента - другая, ну и соотношение клиент:реквизиты типа 1:n; тогда, кмк, такой проблемы не возникает)
показывать список состояний, дать возможность печатать любое из них
(Имхо, в идеале иметь такую структуру БД, в которой клиент - это одна сущность, а реквизиты клиента - другая, ну и соотношение клиент:реквизиты типа 1:n; тогда, кмк, такой проблемы не возникает)термин "сущность" здесь вводит в заблуждение. Лучше пользоваться классической реляционной терминологией. Тогда клиент это не кортеж (сущность а атрибут. Т.е. разделение на клиента и реквизиты просто нет, и связи между ними тоже нет.
(Имхо, в идеале иметь такую структуру БД, в которой клиент - это одна сущность, а реквизиты клиента - другая, ну и соотношение клиент:реквизиты типа 1:n; тогда, кмк, такой проблемы не возникает)а в накладной идет привязка к самому клиенту? или к его реквизитам? Если к клиенту, то как узнать какие реквизиты отображать в накладной?
показывать список состояний, дать возможность печатать любое из нихтакое очень редко требуется, я ни разу не встречал такого.
![](/images/graemlins/smile.gif)
![](/images/graemlins/smile.gif)
И как теперь распечатать накладную с новым адресом?
рядом с кнопкой "Выбор из списка" можно сделать кнопку "Обновить", которая будет привязывать новую версию контрагента.
А так же, это может быть не один документ, а например, пачка документов.
Сделать форму, на которой будут выбираться какие накладные нужно обновить и по кнопке будут проиходить привязка новой версии контрагента.
Смысл в том, что такие изменения должны сопровождаться действиями пользователя. Система не должна действовать в "тихую" -- поменяли адрес контрагента, и адрес поменялся во всех накладных.
обычно (насколько я сталкивался требуется печатать текущую информацию (на момент печати)ты, действительно, с таким сталкивался?
я сталкивался с ситуацией, когда требуется информация не на момент печати, а на момент ввода накладной, точнее, на момент выбора контрагента из списка. А печатать можно сколько угодно и когда угодно.
завести дополнительные поля в накладной, в которые копировать значения из справочника.это самое простое и проверенное решение.
оно верно еще и с той точки зрения, что документ (накладная) когда был подписан начальником, мог быть подписан электронным ключом, то документ не имеет права меняться (в том числе и справочная инфа, использованная при печати).
Как вариант можно завести BLOB'овое поле (не знаю как с этим у 1С) в которое сложить всю подписанную инфу (или инфу на состояние завершения обработки документа) и из которой можно все распечатать на тот момент.
Вообще приходит в голову мысль создать универсальную табличку с отчетами и складывать все распечатанные (и возможно электронно подписанные) отчеты всей системы туда (а из документа - интерфейс с выбором из старых отчетов а не плодить историю для каждого справочника и каждого документа...
почему факт того, что используется электронная подпись, должен влиять на способ программирования системы?
Документ может иметь долгий жизненный цикл, в процессе которого какие-то поля документа могут меняться, а какие-то нет.
а не плодить историю для каждого справочникакакие недостатки?
P.S. я вижу пока недостаток только в некотором усложнении работы со связанными между собой или иерархическими справочниками.
и каждого документа...
об истории документов я не говорил
Подписывается исходный документ, отдельно подписывается каждое последующее изменение. Только так, иначе это не документ.
почему факт того, что используется электронная подпись, должен влиять на способ программирования системы?потому что электронная подпись при достаточной авторизации имеет ту же юридическую силу что и рукописная, а если я подписываю накладную или того хуже платежку, в которой указан контрагент и ты на него ссылаешься по ID/GUID/etc, то просто переименовав контрагента и переписан номера его счетов, не меняя ID, злоумышленик может полностью изменить смысл документа и деньги пойдут не туда.
Если тебе подпись не нужна, то можешь на такие вещи забить, но помнить о них стоит.
В ответ на:каждый справочник тебе придется бить на 2 таблицы: неизменяемая часть и изменяемая часть с датой изменения.
а не плодить историю для каждого справочника
какие недостатки?
P.S. я вижу пока недостаток только в некотором усложнении работы со связанными между собой или иерархическими справочниками.
если откажемся от первой таблицы, то теряется понятие "объект" по отношению к элементу справочника.
причем опять таки такое деление не защищает от подтасовки
и каждого документа...имея хранилище отчетов, ты получаешь эту фичу совершенно бесплатно.
об истории документов я не говорил
если откажемся от первой таблицы, то теряется понятие "объект" по отношению к элементу справочника.и что будет? не вижу ничего страшного
в том числе в self-references'ах (древовидные справочники)...
первичным ключом что будет?
как идентифицировать модификации одного и того же контрагента, например?
ты ссылаться на что будешь в detail'ах?не понял
в том числе в self-references'ах (древовидные справочники)...
да с этим есть проблемы (я упоминал). При изменении родителя создаются новые версии всех потомков.
первичным ключом что будет?
(Бизнес-идентификатор объекта, Время)
как идентифицировать модификации одного и того же контрагента, например?
По бизнес-идентификатору объекта.
дата в первичном ключе - это вообще пример того, как не надо программировать
плюс копировать тонны ненужной инфы в древовидных справочниках, внося еще больше проблем..
первичный ключ из двух полей в справочниках-master'ах - это вообще прямая дорога в ад из глюков и кривизны...
так не делается
вот тебе и приходится придумывать "бизнес-идентификаторы" всякие
нет, дополнительного тут ничего придумывать не надо. Фактически бизнес-идентификаторами я назвал то, что является первичным ключом, когда мы не поддерживается историчность.
нарушать нормализацию
ты, видимо, плохо знаешь, что такое нормализация
дата в первичном ключе - это вообще пример того, как не надо программировать
1. Кто сказал, что в первичный ключ входит поле типа дата? как я уже упоминал, для фиксации моментов времени можно ввести в базе глобальный автоинкремент. В большинстве случаев бизнес-логика завязана не на реальную дату, а на последовательность, в которой данные записывались в базу.
2. Я видел примеры, где поле типа DATETIME входит в первичный ключ. А что в этом плохого? с точки зрения быстродействия, построения индексов, DATETIME занимает 8 байт, также как BIGINТ, не так уж и плохо. Единственная проблема -- использование даты с машинного таймера.
плюс копировать тонны ненужной инфы в древовидных справочниках
а как ты предлагаешь поддерживать историчность иерархических справочников? всю ветку дерева в документ? на мой взгляд, это не лучше. Если подумать и разобраться эта инфа вовсе не лишняя. Лишних записей будет много, если элементы справочника меняются намного чаще, чем по этим элементам проводятся документы, что бывает крайне редко. Обычно база растет в большей степени за счет документов, чем за счет версий справочников.
внося еще больше проблем..
какие?
первичный ключ из двух полей в справочниках-master'ах - это вообще прямая дорога в ад из глюков и кривизны...
так не делается
на это я могу сказать лишь, что это прекрасно работает
![](/images/graemlins/smile.gif)
Кстати, есть предположение, что физически можно не копировать дочерние записи, а создавать вьющку на каждую таблицу-справочник.
![](/images/graemlins/smile.gif)
З.Ы. хорошо, что я в этом проекте не участвую
![](/images/graemlins/smirk.gif)
Оставить комментарий
6yrop
Знакомлюсь сейчас с 1С, смотрю демонстрационный ролик "Пример разработки торговой мини-системы" (внизу страницы ). В примере есть несколько справочников, в том числе Контрагенты, и два типа документа, в том числе расходная накладная. У справочника Контрагенты несколько полей Код, Наименование, ИНН, Адрес. В расходной накладной есть поле Контрагент, которое помечается, как ссылка на справочник Контрагенты, соответственно, при вводе накладной пользователь выбирает контрагента из списка. Теперь вопрос. Что произойдет, если у контрагента поменяется адрес? Накладная была распечатана на бумаге, и там стоит старый адрес. А что мы увидим, если найдем эту накладную в системе и снова распечатаем? Причем, аналогичные вопросы возникают относительно всех других полей.Часто в таких случаях предлагается завести дополнительные поля в накладной, в которые копировать значения из справочника. Это не удобно -- сильно возрастает количество полей. Есть другой вариант -- ввести в справочник дополнительное поле Время (можно просто глобальный автоинкремент куда будет вноситься время заведения записи. И при редактировании записи новая запись будет не перезаписывать старую, а будет создаваться новая запись. Таким образом, на уровне архитектуры можно единообразно поддерживать историчность справочников. Странно, почему в 1С8.0 этого не сделано? Ведь по бизнесу в большинстве случаев поддержка историчности справочников была бы не лишней, а часто просто необходима. (В 1С8.0 это решается через регистры сведений, я еще не разбирался, может это и просто, но выглядит это, покрасней мере, неестественно.)