Как организовать домен?
От: Ocenochka  
Дата: 17.09.11 08:58
Оценка:
Подскажите как лучше реализовать домен:

Есть проедметная область с двумя сущностями "проект документа" и "утвержденный документ".
Обе сущности представляют собой по сути один и тот же документ в разных состояниях.
"Проект документа" — это набор невалидированных полей на которые никто не ссылается, кроме "заявки на рассмотрение проекта документа" (еще одна сущность предметной области, содержит поля: дата подачи, дата рассмотрения, статус).
"Утвержденный документ" — это тот же проект, но в валидном состоянии, плюс иногда может отличаться от проекта парочкой полей. На него ссылается пол базы, просто так его не удалить (отдельный вопрос в p.s.).
(иногда, потому что есть не только проекты документов, но и проекты других сущностей).

Собственно вопрос в том, как это реализовать в коде и реляционной базе.
Инструментарий: .NET, NHibernate, DI.

Я вижу два варианта:
1. сделать практический одинаковый набор классов и таблиц отдельно для проекта и отдельно для утвердженного документа.
Такой вариант мне не очень нравится, т.к. у документов есть множество агрегируемых сущностей — в итоге в базе будет два больших почти одинаковых графа объектов.
2. унаследовать классы от абстрактного "документа" и хранить все в одном наборе таблиц в базе. проект от утвержденного документа отличается столбцом.
То же не нравится, т.к. сущности могут начать расходиться по набору полей и рефакторить потом прилично.

Кто-нибудь знает примеры реализации подобного в крупных или известных системах?

p.s. Дополнительный вопрос в том, как удалять сущности, на которые ссылается половина базы? Я слышал что в 1С это сделано не физическим удалением из базы, а пометкой записи как удаленной. Я сам склоняюсь к такому варианту, но аргументом противников такого метода может быть необходимость в большинстве запросов все время проверять этот статус. Есть еще вариант переносить содержимое удаленной записи в другую таблицу/базу (сложный, на мой взгляд, вариант).
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Люблю ставить оценки.
Re: Как организовать домен?
От: akasoft Россия  
Дата: 18.09.11 10:00
Оценка: 1 (1)
Здравствуйте, Ocenochka, Вы писали:

O> Есть проедметная область с двумя сущностями "проект документа" и "утвержденный документ".

O> Обе сущности представляют собой по сути один и тот же документ в разных состояниях.

А зачем плодить сущности? Почему бы не сделать одну сущность с состоянием?

O> p.s. Дополнительный вопрос в том, как удалять сущности, на которые ссылается половина базы?


Смотря чего хочется получить по ТЗ от удаления.
Физическое отсутствие данных обеспечит вариант с разрыванием ссылок либо с удалением ссылающихся сущностей.
Историю и отслеживание последовательности действий обеспечит наличие признака удаления. Перенос в др. таблицы оптимизирует работу БД, но логика при этом усложняется, т.к. одна и та же сущность будет лежать в нескольких таблицах.
... << RSDN@Home 1.2.0 alpha 5 rev. 1536>> SQL Express 2008 R2
Re[2]: Как организовать домен?
От: Ocenochka  
Дата: 18.09.11 16:29
Оценка:
Здравствуйте, akasoft, Вы писали:

O>> Есть проедметная область с двумя сущностями "проект документа" и "утвержденный документ".

O>> Обе сущности представляют собой по сути один и тот же документ в разных состояниях.
A>А зачем плодить сущности? Почему бы не сделать одну сущность с состоянием?
А в базе тоже хранить в одной таблице? Если да, то я вижу несколько проблем:
1. Для получения всех "утвержденных документов" нужно проверять что документ не был исключен после включения, при этом запрос к БД усложняется до хранимой процедуры либо если хотим логику в коде, то придется доставать всю таблицу и на клиенте с ней работать.
2. Если в "утвержденном документе" есть ссылки и свойства, которых нет в "проекте документа", то сущности уже не так похожи. А если 30% свойств будет отличаться? А если 50%? Тут вроде как здравый смысл рулит, но он у каждого свой. Вот интересно кто что по этому поводу думает.
3. В одной таблице не получится поставить констрейнты на данные (не критично, но все же)
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Люблю ставить оценки.
Re[3]: Как организовать домен?
От: akasoft Россия  
Дата: 18.09.11 18:57
Оценка: 2 (1)
Здравствуйте, Ocenochka, Вы писали:

O> А в базе тоже хранить в одной таблице?


А почему нет.

O> Если да, то я вижу несколько проблем:


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

O> 1. Для получения всех "утвержденных документов" нужно проверять что документ не был исключен после включения, при этом запрос к БД усложняется до хранимой процедуры либо если хотим логику в коде, то придется доставать всю таблицу и на клиенте с ней работать.


По мне это всего-лишь поле типа один бит, т.е.
SELECT * FROM document WHERE approved = true


O> 2. Если в "утвержденном документе" есть ссылки и свойства, которых нет в "проекте документа", то сущности уже не так похожи. А если 30% свойств будет отличаться? А если 50%? Тут вроде как здравый смысл рулит, но он у каждого свой. Вот интересно кто что по этому поводу думает.


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

O> 3. В одной таблице не получится поставить констрейнты на данные (не критично, но все же)


Это замечание моя боевая телепатия не осилила.
... << RSDN@Home 1.2.0 alpha 5 rev. 1536>> SQL Express 2008 R2
Re[4]: Как организовать домен?
От: Ocenochka  
Дата: 18.09.11 19:44
Оценка:
Здравствуйте, akasoft, Вы писали:

O>> Если да, то я вижу несколько проблем:

A>Пока я вижу такую проблему, что ты ТЗ знаешь, но мне его не говоришь. Поэтому в ответах мне придётся прибегать к боевой телепатии.
Это неизбежно в беседах такого рода — все ТЗ я сообщить не могу по понятным причинам. Могу лишь абстрактно обрисовать проблему — есть две сущности предметной области, но они на столько похожи данными и логикой, что вроде бы являются единым.

O>> 1. Для получения всех "утвержденных документов" нужно проверять что документ не был исключен после включения, при этом запрос к БД усложняется до хранимой процедуры либо если хотим логику в коде, то придется доставать всю таблицу и на клиенте с ней работать.

A>По мне это всего-лишь поле типа один бит, т.е.
A>
A>SELECT * FROM document WHERE approved = true
A>

Тут моя вина. Забыл указать, что ТЗ подразумевает хранение истории по утверждению/отклонению документов. Один и тот же документ может утверждаться, потом отклоняться, потом опять утверждаться но уже с некоторыми измененными полями и так много раз. Сейчас это сделано одной записью в таблице на каждое изменение. Простой проверкой статуса не обойтись. Может быть историю нужно было делать по другому, но других красивых вариантов я не нашел.

O>> 2. Если в "утвержденном документе" есть ссылки и свойства, которых нет в "проекте документа", то сущности уже не так похожи. А если 30% свойств будет отличаться? А если 50%? Тут вроде как здравый смысл рулит, но он у каждого свой. Вот интересно кто что по этому поводу думает.

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

К сожалению по моему ТЗ документ могут отклонить (перевести в проект) после утверждения, а потом опять утвердить его же, но слегка изменив.

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


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

O>> 3. В одной таблице не получится поставить констрейнты на данные (не критично, но все же)

A>Это замечание моя боевая телепатия не осилила.

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

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

зы Спасибо за помощь, не смотря на необходимость в телепатии )
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Люблю ставить оценки.
Re[5]: Как организовать домен?
От: hachik  
Дата: 19.09.11 07:19
Оценка: 2 (1)
Здравствуйте, Ocenochka, Вы писали:

O>Здравствуйте, akasoft, Вы писали:


O>>> Если да, то я вижу несколько проблем:

A>>Пока я вижу такую проблему, что ты ТЗ знаешь, но мне его не говоришь. Поэтому в ответах мне придётся прибегать к боевой телепатии.
O> Это неизбежно в беседах такого рода — все ТЗ я сообщить не могу по понятным причинам. Могу лишь абстрактно обрисовать проблему — есть две сущности предметной области, но они на столько похожи данными и логикой, что вроде бы являются единым.

O>>> 1. Для получения всех "утвержденных документов" нужно проверять что документ не был исключен после включения, при этом запрос к БД усложняется до хранимой процедуры либо если хотим логику в коде, то придется доставать всю таблицу и на клиенте с ней работать.

A>>По мне это всего-лишь поле типа один бит, т.е.
A>>
A>>SELECT * FROM document WHERE approved = true
A>>

O> Тут моя вина. Забыл указать, что ТЗ подразумевает хранение истории по утверждению/отклонению документов. Один и тот же документ может утверждаться, потом отклоняться, потом опять утверждаться но уже с некоторыми измененными полями и так много раз. Сейчас это сделано одной записью в таблице на каждое изменение. Простой проверкой статуса не обойтись. Может быть историю нужно было делать по другому, но других красивых вариантов я не нашел.

O>>> 2. Если в "утвержденном документе" есть ссылки и свойства, которых нет в "проекте документа", то сущности уже не так похожи. А если 30% свойств будет отличаться? А если 50%? Тут вроде как здравый смысл рулит, но он у каждого свой. Вот интересно кто что по этому поводу думает.

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


Мне кажется если сделать структуру таблиц более нормализованной то будет проще организовать все в одной схеме. Как уже сказали — ввести состояния.
Взять таблицу Documents, описывающую шапку документа. К ней прикрутить таблицу Versions — с состояниями — в ней же и хранится вся история состояний с документом. Свойства документа — тоже отдельная таблица — properties и таблица связей propToVersion в которой будет связь версии со свойством.
Это примерно в общем виде, наверное косячки есть, можно продумать подробнее. Правда я не знаю как такая структура ложится на ORM
Re[5]: Как организовать домен?
От: bl-blx Россия http://yegodm.blogspot.com
Дата: 19.09.11 10:10
Оценка: 5 (2)
Здравствуйте, Ocenochka, Вы писали:

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

А вам по неутвержденнвм документам поиск по отдельным (любым) полям нужен? Если нет, то можно
попробовать неутвержденный документ в JSON- или XML-форме хранить, как одно большое текстовое поле.
El pueblo unido jamás será vencido.
Re[6]: Как организовать домен?
От: Ocenochka  
Дата: 19.09.11 14:52
Оценка:
Здравствуйте, bl-blx, Вы писали:

BB>А вам по неутвержденнвм документам поиск по отдельным (любым) полям нужен? Если нет, то можно попробовать неутвержденный документ в JSON- или XML-форме хранить, как одно большое текстовое поле.


Такой вариант рассматривали, но поиск нужен.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Люблю ставить оценки.
Re[6]: Как организовать домен?
От: Ocenochka  
Дата: 19.09.11 14:53
Оценка:
Здравствуйте, hachik, Вы писали:

H>Мне кажется если сделать структуру таблиц более нормализованной то будет проще организовать все в одной схеме. Как уже сказали — ввести состояния.

H>Взять таблицу Documents, описывающую шапку документа. К ней прикрутить таблицу Versions — с состояниями — в ней же и хранится вся история состояний с документом. Свойства документа — тоже отдельная таблица — properties и таблица связей propToVersion в которой будет связь версии со свойством.

Да примерно так и вышло. Иерархия таблиц для документа в единственном экземпляре + две таблицы ссылающиеся на документ: 1. проект, 2. утвержденные.

H>Это примерно в общем виде, наверное косячки есть, можно продумать подробнее. Правда я не знаю как такая структура ложится на ORM


На ORM нормально ложится.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Люблю ставить оценки.
Re[2]: Как организовать домен?
От: Ronaldo 9  
Дата: 20.09.11 08:49
Оценка:
Здравствуйте, akasoft, Вы писали:

A>Историю и отслеживание последовательности действий обеспечит наличие признака удаления. Перенос в др. таблицы оптимизирует работу БД, но логика при этом усложняется, т.к. одна и та же сущность будет лежать в нескольких таблицах.


А как насчет сегментирования таблиц?
Re[5]: Начнём с графа состояний
От: akasoft Россия  
Дата: 20.09.11 08:59
Оценка: 2 (1)
Здравствуйте, Ocenochka, Вы писали:

И всё-таки, я пока не вижу, зачем нужно плодить сущности и заводить разные таблицы для "утверждённых" и "неутверждённых" документов.

Для начала изобразим граф озвученных тобой состояний абстрактного документа:
                1                           2                         3
новый_документ --> неутверждённый_документ --> утверждённый_документ --|
                        ^                                              |
                        |----------------------------------------------|


Получаем таблицу документов document(id, state), где state == false, если документ не утверждён, и true, если утверждён. Как я понял, новые документы у тебя не различаются, а получают состояние неутверждённых.

Далее, у документа есть некий набор полей, зависящий от его состояния ихода работ с ним. Эти поля будем хранить в отдельной таблице field(id, doc_id, type, data). Проверять их наличие и обязательность будем в моменты перевода документа из одного состояния в другое, что на графе выше обозначено цифрами от 1 до 3. В каждый такой момент времени мы знаем, какие поля обязательны и какая информация в них допустима.

Для облегчения себе жизни некоторые поля из field можно "втянуть" в document, что упростит работу с документами и немного разгрузит БД, т.к. не понадобится обращаться ко второй таблице. Например, дату создания документа. Или дату последнего изменения.

До сих пор у нас хранится документ в текущем состоянии, а набор и содержание полей зависит от последнего перехода состояния.
Предыдущее состояние документа возникает в момент перехода через то, что обозначено стрелками с цифрами от 1 до 3.

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

От ответов будет зависеть, где и как лучше хранить историю.

Например, мы можем завести доп. поле revision в document и field. Каждый раз при смене состояния мы будем формировать новую строку в этих таблицах, увеличивая на 1 ревизию, а содержание и состав полей будет определяться нашими правилами. Понятно, что для document это будет одна строка, а для field это будет M строк, в общем случае отличных от N строк, привязанных к документу на предыдущем состоянии.

Можно завести по две таблицы document и field. Первый набор — для хранения текущего состояния, как описано выше. Таким образом, мы его всегда быстро вытащим не напрягая БД. А вот второй набор полей будет содержать ревизию: document2 (id, state, revision) и field2 (id, doc_id, type, data, revision), куда строки будут заноситься копированием текущих значений из document/field с увеличением ревизии в моменты переходов состояния. Т.е. сначала спасём текущие данные из document/field в document2/field2 под новой ревизией, затем их поменяем в document/field и получем корректное новое состояние.
У второго подхода выгода в том, что если к истории мы обращаемся реже, чем к текущим данным, то БД будет куда легче обрабатывать "маленькую" таблицу чаще, чем "большую". Разделяй и властвуй.

Можно ещё попробовать хранить только изменения полей, для чего понадобится ещё одна промежуточная таблица между document и field.

Ну а если работа с историей заключается всего-лишь в строчке протокола "20.09.2011 документ отправлен на доработку зам. главы Администрации Сидоровым Г.А.", то дело совсем упрощается. Будем в моменты 1-3 просто заносить этот протокол в отдельную таблицу protocol (id, doc_id, text) и не морочить себе голову.

Ах да, что будет если мы внесём изменения в неутверждённый документ, но состояние при этом останется неутверждённым? А это зависит от ТЗ. Если надо отслеживать и такие изменения, то перерисуем наш граф, добавив связь 4, а написанное выше будет по прежнему иметь силу.

                1                           2                          3
новый_документ --> неутверждённый_документ -|-> утверждённый_документ --|
                        ^-------------------| 4                         |
                        |-----------------------------------------------|
... << RSDN@Home 1.2.0 alpha 5 rev. 1536>> SQL Express 2008 R2
Re[3]: Как организовать домен?
От: akasoft Россия  
Дата: 20.09.11 09:23
Оценка:
Здравствуйте, Ronaldo 9, Вы писали:

R9>А как насчет сегментирования таблиц?


Оставлю его пока на совести БД.
Или ты что-то конкретное имеешь ввиду?
... << RSDN@Home 1.2.0 alpha 5 rev. 1536>> SQL Express 2008 R2
Re[4]: Как организовать домен?
От: Ronaldo 9  
Дата: 20.09.11 10:50
Оценка:
Здравствуйте, akasoft, Вы писали:

A>Здравствуйте, Ronaldo 9, Вы писали:


R9>>А как насчет сегментирования таблиц?


A>Оставлю его пока на совести БД.

A>Или ты что-то конкретное имеешь ввиду?

Просто можно не делить актуальные и удаленные данные на разные таблицы, а сегментировать. Либо просто наложить индекс по флагу "удаленный".
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.