Страницы

Поиск по вопросам

вторник, 17 декабря 2019 г.

Отношение один к разным типам объектов

#java #c_sharp #sql #entity_framework #архитектура


Я не знаю, есть ли какой-то готовый термин, поэтому в заголовок вынес "один-к-разным-типам-объектов",
но это не термин из EF-диаграмм (один-ко-многим, многие-ко-многим и т.п.)

Вот с какой задачей на архитектуру я столкнулся. Меня интересует каким образом можно
выразить (в первую очередь на слое реляционном, во вторую - на уровне классов) отношение
один-к-разным типам объектов.

Пример из практики, несколько упрощённый. В базе данных существует таблица денежных
переводов (MoneyTransfers) между пользователями сайта с полями:


идентификатор перевода MoneyTransferId,
участник-отправитель SourceUserId,
участник-получатель DestinationUserId,
величина перевода AmountRur.


В базе есть таблица заказов (Orders). Это сайт групповых закупок, участники объединяются
для того, чтобы сэкономить на доставке товара из-за рубежа. 

И вот для учёта кто за что кому когда платил (а бардак там бывает знатный, особенно
на какую-нибудь чёрную пятницу) сделана ещё одна таблица, OrderEntries:


идентификатор OrderEntryId,
сумма AmountRur,
идентификатор перевода MoneyTransferId,
идентификатор заказа OrderId.


Т.е. фактически это связь многие-ко-многим между Order и MoneyTransfer с промежуточной
таблицей. Удобно в практике: можно оплатить заказ несколькими переводами, можно одним
переводом оплатить сразу несколько заказов - и по всему этому удобно строить отчёты.

Проблема появляется, когда помимо заказов-закупок девочки захотели продавать друг
другу лачки. Вот тут и появилась вторая таблица в дополнение к Orders — таблица сделок
(Opportunitites), а с ней появилась и проблема, вынесенная в заголовок.

Таблиц у меня две, при этом в OrderEntries мне нужно указать к чему относится эта
запись - к Order или к Opprtunity.

Как быть?

Можно пойти по пути объединения таблиц Order и Opportunity в одну сущность. При этом
допустим такая ORM как Entity Framework предлагает три варианта для хранения данных:
Table Per Hierarchy, Table Per Type и Table Per Concrete Type. Причём все способы имеют
значительные недостатки, либо в удобстве работе, либо с производительностью.

Можно пойти по пути создания на таблице OrderEntry двух полей EntityType и EntityId.
При этом поле EntityType будет иметь низкую селективность, а проконтролировать ограничение
EntityId как внешнего ключа я вообще не представляю себе как.

Другой вариант - сделать на таблице OrderEntry два nullable столбца - один OrderId,
другой OpportunityId и заполнять либо тот, либо другой. Ну, неплохой вариант как кажется.

И последнее, что приходит в голову - это сделать две разных таблицы OrderEntiry -
одна будет OrderEntryForOrder, другая - OrderEntryForOpportunity. Тоже вариант, который
мне нравится, но меньше чем предыдущий: как мне кажется будет сложнее писать запросы
к базе.

Кажется, я перебрал все возможные варианты, ничего не упустил? (Если знаете другой
- напишите)

Меня интересуют какой-то типовой подход (best practice) к решению подобной задачи,
какой вариант более удобен в реальных системах.
    


Ответы

Ответ 1



Можно пойти по пути создания на таблице OrderEntry двух полей EntityType и EntityId. При этом поле EntityType будет иметь низкую селективность, а проконтролировать ограничение EntityId как внешнего ключа я вообще не представляю себе как. Встречал на практике вот этот вариант и он был очень даже работоспособен. Проверка целостности в этом случае, естественно, осуществляется уже не на уровне БД. Индекс должен быть композитный - сразу по двум полям. Другой вариант - сделать на таблице OrderEntry два nullable столбца - один OrderId, другой OpportunityId и заполнять либо тот, либо другой. Ну, неплохой вариант как кажется. Он не масштабируется. В тех системах, с которыми я работал - количество таких таблиц со временем увеличивалось до 20-30. И последнее, что приходит в голову - это сделать две разных таблицы OrderEntiry - одна будет OrderEntryForOrder, другая - OrderEntryForOpportunity. Тоже вариант, который мне нравится, но меньше чем предыдущий: как мне кажется будет сложнее писать запросы к базе. Аналогично.

Комментариев нет:

Отправить комментарий