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

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

25.01.2018, 08:56. Показов 2583. Ответов 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
14367 / 9468 / 1360
Регистрация: 21.01.2016
Сообщений: 35,719
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
14367 / 9468 / 1360
Регистрация: 21.01.2016
Сообщений: 35,719
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
1531 / 532 / 127
Регистрация: 09.01.2018
Сообщений: 1,714
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
1531 / 532 / 127
Регистрация: 09.01.2018
Сообщений: 1,714
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
1531 / 532 / 127
Регистрация: 09.01.2018
Сообщений: 1,714
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
1531 / 532 / 127
Регистрация: 09.01.2018
Сообщений: 1,714
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
Ответ Создать тему
Новые блоги и статьи
сукцессия 29. Переход от одних деревьев на другие делать более или менее вероятностным?
anaschu 12.07.2026
Насколько смена типов микоризы — исключительное событие в двухвековой сукцессии? Оценка вероятности в пространстве параметров В текущей версии модели успешно реализован ключевой механизм. . .
сукцессия 27. Думаю, как переделывать уже написанную статью с планами на сукцессию.
anaschu 12.07.2026
Анализ соответствия модели требованиям Реализованные компоненты: Механизм закисления почвы через протонную помпу Конкуренция между типами микориз pH как триггер сукцессии C/ P соотношение. . .
Сукцессия 26. Мат модель создана.
anaschu 12.07.2026
Модель смены растительных сукцессий посредством управления грибами работает внутри небольшой ячейки почвы, восстанавливающейся после пожара, где ненадолго бывшее царство хвойных снова захватили. . .
Решил проблему с ошибкой пагинации сообщений с сервера на алгоритме обхода дерева "Эстафета хвоста".
Hrethgir 12.07.2026
Проблема была в том, что удалялась именно новая кнопка, а не старая. Ни один ИИ не обнаружил это, а сам я смог только когда с работой стало попроще и когда заставил работать будущее автономное. . .
сукцессия 25. Хронология ошибок
anaschu 12.07.2026
# От 50-тонного гриба до устойчивого леса: хроника ошибок при построении модели вековой сукцессии микоризы ## О чём эта статья В процессе построения ОДУ-модели (система дифференциальных. . .
сукцессия 24. Промежуточное общее описание модели
anaschu 12.07.2026
Хендофф: модель АМ→ЭКМ сукцессии микоризы (ризосфера, 50 лет) Содержание проекта Симуляция вековой (50 лет) экологической сукцессии в почве леса Основные участники: АМ-гриб, ЭКМ-гриб,. . .
сукцессия 23. Более физиологичная физиология, более экологичная экология, более диффурные диффуры.
anaschu 12.07.2026
Что реально нашли и починили за эти 5 часов Правило Линдемана (КПД конверсии сахара в тело, kEff) — раньше 100% полученного углерода шло прямо в биомассу гриба; теперь только kEff=0. 5 (после. . .
сукцессия 22. От артефактов к физиологии: калибровка агентной модели грибной сукцессии для воспроизведения сезонной динамики и pH-плато
anaschu 11.07.2026
Аннотация В данной работе представлена калибровка агентной модели динамики грибных сообществ (fungal-succession), направленная на устранение нефизичных артефактов (коллапс биомассы, мгновенное. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru