#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. Тоже вариант, который мне нравится, но меньше чем предыдущий: как мне кажется будет сложнее писать запросы к базе. Аналогично.
Комментариев нет:
Отправить комментарий