Форум программистов, компьютерный форум, киберфорум
C#: Базы данных
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.64/11: Рейтинг темы: голосов - 11, средняя оценка - 4.64
3 / 3 / 2
Регистрация: 30.07.2017
Сообщений: 223

Как лучше спроектировать отношение "документ-скан" в БД?

25.01.2018, 08:56. Показов 2611. Ответов 34
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день!
В БД есть разные таблицы-сущности. Например, "счет-фактура", "счет", "товарная накладная", "договор". Я хочу создать отдельную таблицу, в которой будут храниться сканы (точнее ссылки на сканы) документов. С отношениями "многие к одному", т.е. у одного документа-сущности может быть несколько сканов. Понимаю, что должна быть таблица-посредник "документ-скан", в которой помимо полей Id, doc_id, scan_id должно быть поле, определяющее к какому именно типу документа относится данный скан. Тут уже становится не понятно

Вторая часть вопроса. Использую NHibernate (предполагаю, что в EF или в любой другой ORM, возник бы подобный вопрос).
Как правильно замаппить данный класс посредник:
C#
1
2
3
4
5
6
public class DocScan 
{
   public virtual int Id {get; set;}
   public virtual Scan Scan {get; set;}
   public virtual Doc Doc {get; set;}
}
Непонятно по последнему полю - как такового типа Doc не существует, т.е. есть, в соответствии с примером, типы Invoice, Contract, PackList и т.д. Как я могу неявно здесь его замаппить? Т.е. надо как-то замаппить его как перечисление допустимых типов. Это вообще возможно?

Пока не очень правильное решение "в лоб" - это дополнить все сущности полями-ссылками на сканы, но тогда это будет отношение "один ко одному" и непонятно как добавлять дополнительные сканы в случае необходимости.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
25.01.2018, 08:56
Ответы с готовыми решениями:

Как лучше спроектировать БД?
Абстрактный вопрос не относящийся к конкретной СУБД. Как быть если нужен список строк в БД? Как то так. Приведу пример: есть сущность -...

Как лучше спроектировать БД
Добрый день. Тут на работе при проектировании БД столкнулся с такой проблемой: Есть физические и юридические лица (отдельные таблицы), и...

Как лучше/правильнее спроектировать
Возникла необходимость переписать старую CRM Что есть сейчас: 1) БД MS SQL а хостинге 3) Web сервис, который на вход получает sql...

34
Эксперт .NET
 Аватар для Usaga
14745 / 9519 / 1364
Регистрация: 21.01.2016
Сообщений: 35,914
30.01.2018, 11:33
Студворк — интернет-сервис помощи студентам
wrq2017, ничего не понял. Так вам один скан надо прикрепить или несколько?
0
3 / 3 / 2
Регистрация: 30.07.2017
Сообщений: 223
30.01.2018, 11:53  [ТС]
Usaga, я предполагаю, что к одному документу должна быть возможность прикреплять от 1 до N сканов.
0
Эксперт .NET
 Аватар для Usaga
14745 / 9519 / 1364
Регистрация: 21.01.2016
Сообщений: 35,914
30.01.2018, 11:54
wrq2017, тогда это не один к одному)
0
3 / 3 / 2
Регистрация: 30.07.2017
Сообщений: 223
30.01.2018, 13:58  [ТС]
Usaga, Я и не говорил, что связь между документом (дочерней сущностью) и сканом "один к одному". Тут явные многие к одному.
Еще раз про схему. Есть базовая сущность "Документ", которая имеет связь как бы "один к одному" с дочерними документарными сущностями, каждая из которых, в свою очередь имеет связь "один ко многим" со сканами.

Добавлено через 7 минут
Сущность "Документ" является генератором ID для дочерних сущностей (Договор, счет и т.п.). Дочерние сущности имеют непересекающийся набор атрибутов, что не позволяет их свести в одну таблицу. В тоже время, некоторые атрибуты общие, что позволяет их оставить в родительской таблице "Документ". По-моему, оптимальное решение
0
 Аватар для Козадоев
165 / 155 / 33
Регистрация: 05.03.2013
Сообщений: 879
30.01.2018, 14:11
Цитата Сообщение от wrq2017 Посмотреть сообщение
Так и есть. У сущности Документ. Получается, что сущность Документ выступает генератором ID для дочерних сущностей.
Ну и в чем проблема тогда?
0
3 / 3 / 2
Регистрация: 30.07.2017
Сообщений: 223
30.01.2018, 14:57  [ТС]
Козадоев, практически нет проблем. Осталось только переработать код на предмет сохранения экземпляров сущностей.
0
 Аватар для Козадоев
165 / 155 / 33
Регистрация: 05.03.2013
Сообщений: 879
30.01.2018, 15:35
Цитата Сообщение от wrq2017 Посмотреть сообщение
практически нет проблем.
Ваша база тривиальна и проблем не должна вызывать. Возможно вы только начинаете и вам кажется что все запутанно и сложно.
0
3 / 3 / 2
Регистрация: 30.07.2017
Сообщений: 223
30.01.2018, 15:42  [ТС]
Цитата Сообщение от Козадоев Посмотреть сообщение
Ваша база тривиальна и проблем не должна вызывать. Возможно вы только начинаете и вам кажется что все запутанно и сложно.
Готов подписаться под каждым словом. Поэтому, как воздух хочется вдыхать устояшийся опыт
0
1534 / 541 / 127
Регистрация: 09.01.2018
Сообщений: 1,758
31.01.2018, 10:26
Лучший ответ Сообщение было отмечено wrq2017 как решение

Решение

wrq2017,
Не рассматривали такой вариант, как не определять внешние ключи для таблицы сканов? У скана есть Id потребителя (еще вариант - поле тип, чтобы не использовать Guid в документах). А при выборке документов просто джойнить сканы по ConsumerId и DocumentType.
1
3 / 3 / 2
Регистрация: 30.07.2017
Сообщений: 223
31.01.2018, 10:58  [ТС]
escoult, я примерно представляю такой вариант с точки зрения чистого SQL, а точки зрения маппинга NHibernate сложновато...
0
1534 / 541 / 127
Регистрация: 09.01.2018
Сообщений: 1,758
31.01.2018, 11:24
wrq2017, С NHibernate я не сталкивался, но думаю смысл будет похожим. Есть контекст данных, через который осуществляется доступ к таблицам. Тогда можно сделать вот так:

C#
1
2
3
4
5
6
7
8
9
10
11
12
var query = from document in _context.SomeDocuments
                   join scan in _context.Scans
                   on document.Id equals scan.ConsumerId 
                   group scan by document
                   into documentVM
                   select new SomeDocumentViewModel
                  {
                      Id = documentVM.Key.Id,
                      DocumentName = documentVM.Key.DocumentName,
                      Scans = from scan in documentVM
                                     select scan
                  };
1
3 / 3 / 2
Регистрация: 30.07.2017
Сообщений: 223
31.01.2018, 15:49  [ТС]
escoult, спасибо, с запросом вопросов нет. Сейчас попробую всё это дело замаппить.

Добавлено через 1 час 20 минут
Уважаемые господа и дамы!
Сделал сущность Scan так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
  public class Scan: Entity
    {
        public virtual int DocumentID { get; set; }
        public virtual TypeOfEntity TypeOfEntity { get; set; }
        public override bool Equals(object obj)
        {
            return Equals(obj as Scan);
        }
        private bool Equals(Scan other)
        {
            if (ReferenceEquals(other, null)) return false;
            if (ReferenceEquals(this, other)) return true;
 
            return DocumentID == other.DocumentID &&
                TypeOfEntity == other.TypeOfEntity;
        }
        public override int GetHashCode()
        {
            unchecked
            {
                int hash = GetType().GetHashCode();
                hash = (hash * 31) ^ DocumentID.GetHashCode();
                hash = (hash * 31) ^ TypeOfEntity.GetHashCode();
                return hash;
            }
        }
    }
 
    public class ScanMap : ClassMap<Scan>
    {
        public ScanMap()
        {
            CompositeId()
                .KeyProperty(x => x.DocumentID, "document_id")
                .KeyReference (x => x.TypeOfEntity, "typeOfEntity_id");
            Map(x => x.Description).Column("description");
            Table("Scan");
        }
    }
Добавлено через 6 минут
Где DocumentID и TypeOfEntity в совокупности представляют составной внешний ключ, и внезапно возник вопрос - а зачем вообще нужен этот ключ, если для фильтрации я могу использовать оба поля?
0
1534 / 541 / 127
Регистрация: 09.01.2018
Сообщений: 1,758
01.02.2018, 02:47
Лучший ответ Сообщение было отмечено wrq2017 как решение

Решение

wrq2017, внешние ключи, как и другие ключи нужны для обеспечения целостности данных. Вопрос достаточно обширный, можете в интернете почитать по этой теме более подробно. Вкратце, внешний ключ является ограничением. Например, если в вашем проекте у таблицы сканов есть поле DocumentId, которое является внешним ключом, это значит, что СУБД не позволит внести в него значения которого нет в главной таблице. А если такой ключ не определен, то вы можете внести любые значения. Что не есть хорошо и нарушит целостность данных. Кроме того, можно определить поведение при удалении данных в главной таблице ну и так далее, более подробно, как уже говорил, читайте в гугле. Возвращаясь к внешнему ключу, в вашем случае, имеется одна таблица, которая ссылается сразу на несколько таблиц. Есть разные подходы для реализации подобной задачи. Наследование, через дополнительную таблицу, есть еще какие то варианты скорее всего. Это называется полиморфная связь. Но суть одна. Дело в том, что фильтрацию данных вы на самом деле можете выполнить без внешних ключей. Можно даже написать какой то сервис, который будет такую фильтрацию проводить и возвращать коллекцию. Однако должна быть соблюдена и целостность данных. В том варианте, что я вам предложил, забота о проверке существования ConsumerId и каскадное удаление перекладывается на код. Хорошо это или плохо зависит скорее всего от потребностей проекта.
Сам лично, я такие варианты (полиморфные связи) использовал только ради интереса в испытательных и образовательных целях. В проектах же я таких вещей избегаю, и пользуюсь наследованием. К примеру в вашем варианте есть разные документы и скан. Это картинка, везде для всех одинаковая. Я бы определил абстрактный класс Document, и класс Scan, с внешним ключом на DocumentId. Все, а дальше от абстрактного класса можно наследовать счет, счет фактура, какой то там еще счет. Они могут никак не иметь общих характеристик по полям, как вы пишите (хотя это не так, id и name будет у всех), тем не менее они могут все быть унаследованы от базового абстрактного класса и быть документами. И все, проблема решается. Скан содержит внешний ключ на документ, можно организовать каскадное удаление, подгрузку объектов навигационных свойств. И целостность данных соблюдена.
1
3 / 3 / 2
Регистрация: 30.07.2017
Сообщений: 223
01.02.2018, 10:13  [ТС]
escoult, да, вариант с абстрактным классом Document тоже хорош, собственно, я его уже и начал реализовывать. Теперь не знаю, какой из двух вариантов выбрать
Вопрос про вариант с абстрактным классом. Правильно ли я понимаю, что, как я уже раньше здесь писал, в этом случае, с точки зрения БД, должна быть организована связь "один к одному" между таблицей Document и таблицами дочерних документов?

Добавлено через 2 минуты
В таком случае, перед тем, как создать дочернюю запись в БД, я сначала должен создать родителя?
0
1534 / 541 / 127
Регистрация: 09.01.2018
Сообщений: 1,758
01.02.2018, 11:14
wrq2017, Если будете реализовывать наследование TPT, то да, все верно. Я в сообщении выше имел ввиду наследование TPH.

Цитата Сообщение от wrq2017 Посмотреть сообщение
В таком случае, перед тем, как создать дочернюю запись в БД, я сначала должен создать родителя?
Насчет этого уверенно ответить не могу, поскольку не знаком с NHibernate вообще никак. Но в теории такого быть не должно. Для чего нужна ORM, если всю черновую работу придется делать самому. Наследование на то и наследование, унаследованная сущность имеет поля родителя. Это с точки зрения СУБД она размещена в разных таблицах. А с точки зрения потребителя, ему должно быть все равно как сущность будет сохраняться. Конечно, почитайте документацию. Но я думаю что нет, такого быть не должно. Есть контекст, ему отдается сущность, а сохранять ее он будет так как определено в конфигурации. На одном конце должна быть СУБД, а на другом прозрачная работа с наследованием.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
01.02.2018, 11:14

Как лучше спроектировать форму?
У меня есть база Access подключенная к Делфи. База содержит данные по квартирам и квартплату. После вычисления квартплаты в таблицу...

Как лучше спроектировать базу данных?
Начал писать и не знаю как лучше спроектировать базу данных. Есть пользователи, они могут создавать задачи(создатель у задачи один). ...

Как лучше спроектировать одну из таблиц?
Помогите пожалуйста разобраться.. Есть заявление на ремонт: код клиента, чего сдает, номер и т. д. А вот комплектность, как лучше...

Как лучше спроектировать систему подписки?
Здравствуйте. Может кто подскажет, как лучше спроектировать систему подписки, что б ее было не стыдно показать? Есть на сайте...

Как лучше спроектировать приложение WPF
Добрый день, вот возник вопрос как лучше спроектировать приложение. Задумка состоит в том что есть панель с кнопками, и при нажатие на...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
35
Ответ Создать тему
Новые блоги и статьи
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
[EasyBuilder Pro] Памятка по разработке для панелей Weintek
ФедосеевПавел 26.08.2026
Памятка по разработке для панелей Weintek ВВЕДЕНИЕ Ранее, при реализации проектов основное внимание уделял разработке управляющей программы для контроллера, а панели оператора доставалось время. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru