Как сделать так, чтобы моя база данных SQL соответствовала дизайну, управляемому доменом - PullRequest
2 голосов
/ 06 мая 2009

Хорошо, я буду откровенен с вами, ребята: я не совсем уверен, как мой проект управляется с помощью домена, но я начал с создания объектов Model и вообще игнорировал слой постоянства. Теперь у меня возникают трудности с выбором наилучшего способа построения таблиц в SQL Server для соответствия моделям.

Я создаю веб-приложение в ASP.NET MVC, хотя не думаю, что платформа имеет такое большое значение. У меня есть следующая иерархия объектной модели:

<b>Property</b> - has properties such as Address and Postcode

 which have one or more

<b>Case</b> - inherits from PropertyObject
<b>Quote</b> - inherits from PropertyObject

 which have one or more 

<b>Message</b> - simple class that has properties Reference, Text and SentDate

У Case и Quote много похожих свойств, поэтому у меня также есть абстрактный базовый класс PropertyObject, от которого они наследуют. Поэтому Property имеет свойство Items типа List, которое может содержать объекты Case и Quote.

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

PropertyObject имеет свойство Reference (и, следовательно, так же и Quote и Case), поэтому любой объект Message может быть связан обратно с Quote или Case его свойством Reference.

Я подумываю об использовании Entity Framework для ввода и вывода моих моделей из базы данных.

Вначале у меня были четыре таблицы: свойство, случай, цитата и сообщение.

Все они будут иметь свои собственные последовательные идентификаторы, а Дело и Предложение будут связаны обратно с Свойством полем PropertyID.

Единственный способ связать таблицу сообщений с таблицами Case и Quote - это иметь поля RelationID и RelationType, но нет очевидного способа сообщить серверу SQL, как работают эти отношения, поэтому я выиграл ' не имеет ссылочной целостности.

Есть идеи, предложения, помощь?

Спасибо, Anthony

Ответы [ 3 ]

1 голос
/ 06 мая 2009

Я предполагаю, что Property также не наследуется от PropertyObject.

Учитывая, что эти таблицы Свойство, Дело, Цитата и Сообщение приводят к стратегии наследования таблицы для конкретного класса или TPC, которую я обычно не рекомендую.

Я рекомендую использовать либо:

  • Таблица для иерархии или TPH - регистр и кавычка хранятся в одной таблице с одним столбцом, используемым в качестве дискриминатора, с обнуляемыми столбцами для свойств, которые не являются общими.
  • Таблица для каждого типа или TPT - добавьте таблицу PropertyObject с общими полями, а также таблицы Case и Quote с дополнительными полями для этих типов

Обе эти стратегии позволят вам поддерживать ссылочную целостность и поддерживаются большинством ORM.

см. Подробнее: Совет 12 - Как выбрать стратегию наследования

Надеюсь, это поможет Alex

1 голос
/ 06 мая 2009

Аааа ... Абстракция.

Уловка с DDD заключается в том, чтобы признать, что абстракция не всегда является вашим другом. В некоторых случаях слишком большая абстракция приводит к слишком сложной реляционной модели.

Вам не всегда нужно наследование. Действительно, основная цель наследования - повторное использование кода. Повторное использование структуры может быть важным, но менее важным.

У вас есть выдающаяся пара отношений: Case IS-A Property и Quote IS-A Property.

У вас есть несколько способов реализовать иерархии классов и отношения "is-a".

  1. Как вы предложили с дискриминаторами типов, чтобы показать, какой это подкласс на самом деле. Это работает, когда вам часто приходится создавать объединение различных подклассов. Если вам нужны все свойства - объединение CaseProperty и QuoteProperty, то это может сработать.

  2. Вам не нужно полагаться на наследство; Вы можете иметь непересекающиеся таблицы для каждого набора отношений. CaseProperty и QuoteProperty. Вы также должны были бы CaseMessage и QuoteMessage, чтобы следовать различию вперед.

  3. Вы можете иметь общие функции в общей таблице и отдельные функции в отдельной таблице, а также выполнять объединение для восстановления одного объекта. Таким образом, у вас может быть таблица Property с общими характеристиками всех свойств, плюс CaseProperty и QuoteProperty с уникальными функциями каждого подкласса Property. Это похоже на то, что вы предлагаете для Case и Quote, имеющих внешние ключи для Property.

  4. Вы можете сгладить полиморфную иерархию классов в одну таблицу и использовать дискриминатор типов и NULL. Основная таблица Property имеет дискриминатор типов для Case и Quote. Атрибуты Case обнуляются для строк, которые должны быть Quote. Аналогично, атрибуты Quote обнуляются для строк, которые должны быть Case.

Ваш вопрос «[как] связать таблицу сообщений обратно с таблицами Case и Quote» связан с полиморфным набором подпунктов. В этом случае лучшее решение может быть следующим.

Message имеет ссылку FK на Property.

Property имеет дискриминатор типа для отделения Quote от Case. Оба определения классов Quote и Case отображаются на Property, но полагаются на дискриминатор типов и (обычно) разные наборы столбцов.

Дело в том, что ответственность за Property, CaseProperty и QuoteProperty принадлежит этой иерархии классов, а не Message.

0 голосов
/ 06 мая 2009

Именно здесь должна появиться концепция Служб DDD. Хранилище для каждого из ваших конкретных классов сохраняет только эту сущность, а не связанные объекты.

Итак, у вас есть Property (), и это база для вашего CaseProperty (): Property (). Доступ к этой специальной сущности осуществляется через CasePropertyService (). Здесь вы найдете свои JOIN и другие связанные таблицы, чтобы сгенерировать специальную сущность CaseProperty () (которая на самом деле не является Case () и свойством самостоятельно, а является комбинацией).

OT: из-за ограничения .net, где вы не можете наследовать несколько классов, это моя работа. DDD является ориентиром для общего понимания вашего домена. Я часто даю свой DDD набросок друзьям, и они пытаются выяснить, что он делает / представляет. Если это выглядит чистым, и они понимают это, это чисто. Если ваши друзья посмотрят на это и скажут: «Я понятия не имею, что вы пытаетесь здесь сохранить». затем вернитесь к чертежной доске.

Но есть ловушка при использовании любого ORM для сохранения хранилища объектов DDD (linq, EntityFramework и т. Д.). Посмотрите на мой ответ здесь:

Stackoverflow: вопрос о репозиториях и методах их сохранения для доменных объектов

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

Я недавно отказался от использования ORM для управления прямым доступом, и у меня просто чистый слой DDD. Я позволяю своим репозиториям и сервисам контролировать доступ к слою БД и использую Velocity для кэширования сущностей моих объектов. Это на самом деле работает очень хорошо для: 1) производительности БД, однако вы проектируете ее наиболее эффективно, не будучи связанным с вашими объектами DOmain с прямым представлением ORM, и 2) ваша модель предметной области становится намного чище без принудительных идентификаторов для объектов-значений и тому подобное. Бесплатно!

...