Entity Framework и дизайн многопользовательской базы данных - PullRequest
7 голосов
/ 30 мая 2010

Я смотрю на проект схемы мультитенантной базы данных для концепции SaaS. Это будет ASP.NET MVC -> EF, но это не так важно.

Ниже приведен пример схемы базы данных (Арендатором является Компания). CompanyId реплицируется по всей схеме, и первичный ключ помещен как в естественный ключ, так и в идентификатор клиента.

При подключении этой схемы к Entity Framework при добавлении таблиц в файл модели объектов (Model1.edmx) возникают следующие ошибки:

  • Отношение «FK_Order_Customer» использует набор внешних ключей «{CustomerId, CompanyId}», которые частично содержатся в наборе первичных ключей «{OrderId, CompanyId}» таблицы «Заказ». Набор внешних ключей должен полностью содержаться в наборе первичных ключей или полностью не содержаться в наборе первичных ключей для сопоставления с моделью.
  • Отношение «FK_OrderLine_Customer» использует набор внешних ключей «{CustomerId, CompanyId}», которые частично содержатся в наборе первичных ключей «{OrderLineId, CompanyId}» таблицы «OrderLine». Набор внешних ключей должен полностью содержаться в наборе первичных ключей или полностью не содержаться в наборе первичных ключей для сопоставления с моделью.
  • Отношение «FK_OrderLine_Order» использует набор внешних ключей «{OrderId, CompanyId}», которые частично содержатся в наборе первичных ключей «{OrderLineId, CompanyId}» таблицы «OrderLine». Набор внешних ключей должен полностью содержаться в наборе первичных ключей или полностью не содержаться в наборе первичных ключей для сопоставления с моделью.
  • Отношение «FK_Order_Customer» использует набор внешних ключей «{CustomerId, CompanyId}», которые частично содержатся в наборе первичных ключей «{OrderId, CompanyId}» таблицы «Заказ». Набор внешних ключей должен полностью содержаться в наборе первичных ключей или полностью не содержаться в наборе первичных ключей для сопоставления с моделью.
  • Отношение «FK_OrderLine_Customer» использует набор внешних ключей «{CustomerId, CompanyId}», которые частично содержатся в наборе первичных ключей «{OrderLineId, CompanyId}» таблицы «OrderLine». Набор внешних ключей должен полностью содержаться в наборе первичных ключей или полностью не содержаться в наборе первичных ключей для сопоставления с моделью.
  • Отношение «FK_OrderLine_Order» использует набор внешних ключей «{OrderId, CompanyId}», которые частично содержатся в наборе первичных ключей «{OrderLineId, CompanyId}» таблицы «OrderLine». Набор внешних ключей должен полностью содержаться в наборе первичных ключей или полностью не содержаться в наборе первичных ключей для сопоставления с моделью.
  • Отношение «FK_OrderLine_Product» использует набор внешних ключей «{ProductId, CompanyId}», которые частично содержатся в наборе первичных ключей «{OrderLineId, CompanyId}» таблицы «OrderLine». Набор внешних ключей должен полностью содержаться в наборе первичных ключей или полностью не содержаться в наборе первичных ключей для сопоставления с моделью.

Вопрос состоит из двух частей:

  1. Неправильный ли дизайн моей базы данных? Должен ли я воздерживаться от этих составных первичных ключей? Я подвергаю сомнению мое здравомыслие относительно фундаментальной схемы проекта (синдром измученного мозга). Пожалуйста, не стесняйтесь предложить «идеализированную» схему.
  2. В качестве альтернативы, если структура базы данных правильная, тогда EF не может сопоставить ключи, потому что он воспринимает эти внешние ключи как потенциально неверно настроенные отношения 1: 1 (неправильно)? В каком случае это ошибка EF и как ее обойти?

Схема мультитенантной базы данных http://i46.tinypic.com/23si52u.png

Ответы [ 5 ]

4 голосов
/ 30 мая 2010

При быстром сканировании сообщений об ошибках EF явно не нравится, как вы настраиваете составные ключи, и я думаю, что это, вероятно, подталкивает вас в правильном направлении. Подумайте еще раз о том, что делает ваши первичные ключи уникальными. Один OrderID не уникален, без CompanyID? Является ли ProductID не уникальным без CompanyID? Линия заказа, безусловно, должна быть уникальной без идентификатора компании, поскольку линия заказа должна быть связана только с одним заказом.

Если вам действительно нужен CompanyID для всего этого, что, вероятно, означает, что данная компания предоставляет вам ProductID и OrderID, тогда вы можете пойти в другом направлении и сгенерировать свои собственные первичные ключи, которые не являются внутренними. к данным. Просто установите столбец автоинкремента для вашего первичного ключа, и пусть они будут внутренними OrderID, OrderLineID, ProductID, CompanyID и т. Д. В этот момент OrderLine не понадобится OrderID или CompanyID клиента; ссылка на внешний ключ для Заказа будет его отправной точкой. (И CustomerID никогда не должен быть атрибутом строки заказа; это атрибут заказа, а не строки заказа.)

Составные ключи просто беспорядочные. Попробуйте разработать модель без них и посмотрите, упрощает ли она вещи.

2 голосов
/ 12 ноября 2010

Я думаю, что ошибка не в дизайне. Не в EF. Находится в отношениях с Sql Server.

Прочитать сообщение EF:

Отношение 'FK_Order_Customer' использует набор внешних ключей '{CustomerId, CompanyId}', которые частично содержится в наборе первичные ключи '{OrderId, CompanyId}' из стол «Заказ». Множество иностранных ключи должны полностью содержаться в набор первичных ключей или не полностью содержится в наборе первичных ключей быть сопоставленным с моделью.

ERROR

На самом деле отношение между Заказом и Клиентом использует только одно поле (возможно, вы перетащили мышью поле «CustomerId» из таблицы «Заказ» в «Идентификатор» таблицы «Клиент»)

РЕШЕНИЕ

Щелкните правой кнопкой мыши по проводу, соединяющему Заказ и Заказчика, и в связи добавьте также CompanyId


PS: дизайн правильный.

Размещение CompanyId в каждой таблице является решением для мультитенантной архитектуры, поскольку помогает масштабировать (обычно всегда требуется выбирать только записи из компании, вошедшей в систему).

2 голосов
/ 30 мая 2010

Я думаю, что сохранение номера компании в каждой из таблиц приносит вам больше вреда, чем помощи. Я могу понять, почему вы хотите это сделать (как программист / dba, вы можете просто зайти в любую таблицу и «посмотреть», какие данные принадлежат тому, кто утешает), но это мешает вам настроить базу данных. так и должно быть.

Избегайте составных ключей, и ваш дизайн станет намного проще.

0 голосов
/ 26 октября 2013

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

Во-вторых, я не могу представить, чтобы не использовался столбец CompanyID в большинстве таблиц в серьезном приложении. Orderdetail может возможно быть исключением в этом случае (возможно, также и глобальные таблицы поиска, если только они не зависят от арендатора). Дело в том, что вы не можете выполнять какой-либо безопасный вид поиска в свободной форме по таблице без добавления CompanyID или выполнения JOIN до тех пор, пока не достигнете точки, в которой есть этот столбец. Последний явно стоит производительности. Возможно, в этом случае вы могли бы сделать исключение для orderdetail и искать только в объединенной версии (только две таблицы). С другой стороны, это не совсем соответствует.

Также относительно того, чтобы сделать его составным ключом или нет: это возможно, но открывает вероятность того, что ошибка записывает информацию неправильно (в несуществующие или другие администрации) на время ошибки. Попытайтесь исправить это на производстве, не говоря уже о том, чтобы объяснить покупателям, почему в их системе наблюдаются заказы их конкурентов.

0 голосов
/ 26 августа 2013

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

Как уже упоминалось, также создайте некластеризованный индекс по идентификатору компании, так что присоединения к таблице компании будут полезны.

Спасибо!

...