[Архитектура] Историчность справочников в системах оперативного учета

6yrop

Знакомлюсь сейчас с 1С, смотрю демонстрационный ролик "Пример разработки торговой мини-системы" (внизу страницы ). В примере есть несколько справочников, в том числе Контрагенты, и два типа документа, в том числе расходная накладная. У справочника Контрагенты несколько полей Код, Наименование, ИНН, Адрес. В расходной накладной есть поле Контрагент, которое помечается, как ссылка на справочник Контрагенты, соответственно, при вводе накладной пользователь выбирает контрагента из списка. Теперь вопрос. Что произойдет, если у контрагента поменяется адрес? Накладная была распечатана на бумаге, и там стоит старый адрес. А что мы увидим, если найдем эту накладную в системе и снова распечатаем? Причем, аналогичные вопросы возникают относительно всех других полей.
Часто в таких случаях предлагается завести дополнительные поля в накладной, в которые копировать значения из справочника. Это не удобно -- сильно возрастает количество полей. Есть другой вариант -- ввести в справочник дополнительное поле Время (можно просто глобальный автоинкремент куда будет вноситься время заведения записи. И при редактировании записи новая запись будет не перезаписывать старую, а будет создаваться новая запись. Таким образом, на уровне архитектуры можно единообразно поддерживать историчность справочников. Странно, почему в 1С8.0 этого не сделано? Ведь по бизнесу в большинстве случаев поддержка историчности справочников была бы не лишней, а часто просто необходима. (В 1С8.0 это решается через регистры сведений, я еще не разбирался, может это и просто, но выглядит это, покрасней мере, неестественно.)

6yrop

никто с этим не сталкивался?
или я не очень понятно описал проблему?

trobak

Знакомая проблема (правда я с 1С не работал)
Если будешь делать хранения всей истории версий записей, то задумайся на тем, "чего хочет юзер", например, вот в такой ситуации (имхо, вполне вероятной):
Юзер-бухгалтер печатает накладную, видит в ней старый адрес, и понимает что он устарел. Тогда он идет в справочник контрагентов, меняет там адрес (тем самым создается новая версия записи в справочнике контрагентов а накладная-то уже сохранена со ссылкой на предыдущую версию записи клиента. И как теперь распечатать накладную с новым адресом?

Andr163

записи разные, но объект один, ссылка должна быть на объект, а не на запись

trobak

короче, при смене адреса контрагента юзер может захотеть печатать накладную как со старым адресом, так и с новым.
И мой вопрос в том, как грамотно ( чтобы юзеру понятно было) эти случаи различать, в случае если у нас ведется история изменения записей?
А так же, это может быть не один документ, а например, пачка документов.
(Имхо, в идеале иметь такую структуру БД, в которой клиент - это одна сущность, а реквизиты клиента - другая, ну и соотношение клиент:реквизиты типа 1:n; тогда, кмк, такой проблемы не возникает)

Andr163

показывать список состояний, дать возможность печатать любое из них

6yrop

(Имхо, в идеале иметь такую структуру БД, в которой клиент - это одна сущность, а реквизиты клиента - другая, ну и соотношение клиент:реквизиты типа 1:n; тогда, кмк, такой проблемы не возникает)
термин "сущность" здесь вводит в заблуждение. Лучше пользоваться классической реляционной терминологией. Тогда клиент это не кортеж (сущность а атрибут. Т.е. разделение на клиента и реквизиты просто нет, и связи между ними тоже нет.

6yrop

(Имхо, в идеале иметь такую структуру БД, в которой клиент - это одна сущность, а реквизиты клиента - другая, ну и соотношение клиент:реквизиты типа 1:n; тогда, кмк, такой проблемы не возникает)
а в накладной идет привязка к самому клиенту? или к его реквизитам? Если к клиенту, то как узнать какие реквизиты отображать в накладной?

6yrop

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

Andr163

обычно (насколько я сталкивался требуется печатать текущую информацию (на момент печати)

Andr163

просмотр - да, печать - нет

6yrop

И как теперь распечатать накладную с новым адресом?

рядом с кнопкой "Выбор из списка" можно сделать кнопку "Обновить", которая будет привязывать новую версию контрагента.
А так же, это может быть не один документ, а например, пачка документов.

Сделать форму, на которой будут выбираться какие накладные нужно обновить и по кнопке будут проиходить привязка новой версии контрагента.
Смысл в том, что такие изменения должны сопровождаться действиями пользователя. Система не должна действовать в "тихую" -- поменяли адрес контрагента, и адрес поменялся во всех накладных.

6yrop

обычно (насколько я сталкивался требуется печатать текущую информацию (на момент печати)
ты, действительно, с таким сталкивался?
я сталкивался с ситуацией, когда требуется информация не на момент печати, а на момент ввода накладной, точнее, на момент выбора контрагента из списка. А печатать можно сколько угодно и когда угодно.

gopnik1994

завести дополнительные поля в накладной, в которые копировать значения из справочника.
это самое простое и проверенное решение.
оно верно еще и с той точки зрения, что документ (накладная) когда был подписан начальником, мог быть подписан электронным ключом, то документ не имеет права меняться (в том числе и справочная инфа, использованная при печати).
Как вариант можно завести BLOB'овое поле (не знаю как с этим у 1С) в которое сложить всю подписанную инфу (или инфу на состояние завершения обработки документа) и из которой можно все распечатать на тот момент.
Вообще приходит в голову мысль создать универсальную табличку с отчетами и складывать все распечатанные (и возможно электронно подписанные) отчеты всей системы туда (а из документа - интерфейс с выбором из старых отчетов а не плодить историю для каждого справочника и каждого документа...

6yrop

почему факт того, что используется электронная подпись, должен влиять на способ программирования системы?

6yrop

Документ может иметь долгий жизненный цикл, в процессе которого какие-то поля документа могут меняться, а какие-то нет.

6yrop

а не плодить историю для каждого справочника
какие недостатки?
P.S. я вижу пока недостаток только в некотором усложнении работы со связанными между собой или иерархическими справочниками.

6yrop

и каждого документа...

об истории документов я не говорил

ava3443

Подписывается исходный документ, отдельно подписывается каждое последующее изменение. Только так, иначе это не документ.

gopnik1994

почему факт того, что используется электронная подпись, должен влиять на способ программирования системы?
потому что электронная подпись при достаточной авторизации имеет ту же юридическую силу что и рукописная, а если я подписываю накладную или того хуже платежку, в которой указан контрагент и ты на него ссылаешься по ID/GUID/etc, то просто переименовав контрагента и переписан номера его счетов, не меняя ID, злоумышленик может полностью изменить смысл документа и деньги пойдут не туда.
Если тебе подпись не нужна, то можешь на такие вещи забить, но помнить о них стоит.

gopnik1994

В ответ на:
а не плодить историю для каждого справочника
какие недостатки?
P.S. я вижу пока недостаток только в некотором усложнении работы со связанными между собой или иерархическими справочниками.
каждый справочник тебе придется бить на 2 таблицы: неизменяемая часть и изменяемая часть с датой изменения.
если откажемся от первой таблицы, то теряется понятие "объект" по отношению к элементу справочника.
причем опять таки такое деление не защищает от подтасовки

gopnik1994

и каждого документа...
об истории документов я не говорил
имея хранилище отчетов, ты получаешь эту фичу совершенно бесплатно.

6yrop

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

gopnik1994

ты ссылаться на что будешь в detail'ах?
в том числе в self-references'ах (древовидные справочники)...
первичным ключом что будет?
как идентифицировать модификации одного и того же контрагента, например?

6yrop

ты ссылаться на что будешь в detail'ах?
не понял
 
в том числе в self-references'ах (древовидные справочники)...

да с этим есть проблемы (я упоминал). При изменении родителя создаются новые версии всех потомков.
 
первичным ключом что будет?

(Бизнес-идентификатор объекта, Время)
 
как идентифицировать модификации одного и того же контрагента, например?

По бизнес-идентификатору объекта.

gopnik1994

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

6yrop

 
вот тебе и приходится придумывать "бизнес-идентификаторы" всякие

нет, дополнительного тут ничего придумывать не надо. Фактически бизнес-идентификаторами я назвал то, что является первичным ключом, когда мы не поддерживается историчность.
нарушать нормализацию

ты, видимо, плохо знаешь, что такое нормализация
 
дата в первичном ключе - это вообще пример того, как не надо программировать

1. Кто сказал, что в первичный ключ входит поле типа дата? как я уже упоминал, для фиксации моментов времени можно ввести в базе глобальный автоинкремент. В большинстве случаев бизнес-логика завязана не на реальную дату, а на последовательность, в которой данные записывались в базу.
2. Я видел примеры, где поле типа DATETIME входит в первичный ключ. А что в этом плохого? с точки зрения быстродействия, построения индексов, DATETIME занимает 8 байт, также как BIGINТ, не так уж и плохо. Единственная проблема -- использование даты с машинного таймера.
 
плюс копировать тонны ненужной инфы в древовидных справочниках

а как ты предлагаешь поддерживать историчность иерархических справочников? всю ветку дерева в документ? на мой взгляд, это не лучше. Если подумать и разобраться эта инфа вовсе не лишняя. Лишних записей будет много, если элементы справочника меняются намного чаще, чем по этим элементам проводятся документы, что бывает крайне редко. Обычно база растет в большей степени за счет документов, чем за счет версий справочников.
 
внося еще больше проблем..

какие?
 
первичный ключ из двух полей в справочниках-master'ах - это вообще прямая дорога в ад из глюков и кривизны...
так не делается

на это я могу сказать лишь, что это прекрасно работает

6yrop

Кстати, есть предположение, что физически можно не копировать дочерние записи, а создавать вьющку на каждую таблицу-справочник.

gopnik1994

бог тебе судья
З.Ы. хорошо, что я в этом проекте не участвую
Оставить комментарий
Имя или ник:
Комментарий: