Хранение унаследованных объектов в базе данных - PullRequest
4 голосов
/ 09 сентября 2010

Я пытаюсь найти лучший способ отобразить отношения наследования в объектной модели в реляционную базу данных. Например, рассмотрим следующую структуру класса.

public Class Item 
{
    public String Name{get; set;}
    public int Size {get; set}    
}

public Class Widget:Item
{
    public String Color{get; set;}
}

public Class Doohicky:Item
{
    public String Smell{get; set;}
}

Вот несколько вариантов, которые я рассматриваю, как сохранить эту структуру в базе данных.

Параметры 1: одна таблица для всех типов элементов

Items Table: ItemID, Name, Color, Smell

Это отстой, так как потребует значений NULL.

Варианты 2: отдельные таблицы для каждого типа элемента

Widgets Table: WidgetID, Name, Color
Doohicky Table: DoohickyID, Name, Smell

Это лучше, но будет сложнее перечислить все предметы

Опции 3: Связанные таблицы

Items Table: ItemID (PK), Name, Size
Widgets Table: WidgetID (PK), ItemID (FK), Color
Doohicky Table: DoohickyID (PK), ItemID (FK), Smell

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

Однако я не уверен, как создать связь между таблицей Предметов и таблицами Виджеты и Doohickies. Я не хочу в конечном итоге строки в любой таблице, ссылающиеся на тот же ItemID в таблице элементов.

Например, когда я добавляю запись в таблицу виджетов, как я могу убедиться, что она связана с новой записью в таблице элементов с уникальным ItemID? Стоит ли вместо этого отслеживать только ItemID, а не отдельные идентификаторы типа, такие как WidgetID и DoohickyID, и использовать его для создания однозначных отношений между таблицей Items и таблицами конкретного типа?

Опции 4

Items Table: ItemID (PK), Name, Size
Widgets Table: ItemID (PK), Color
Doohicky Table: ItemID (PK), Smell

Ответы [ 3 ]

6 голосов
/ 09 сентября 2010

Вы описываете Наследование для одной таблицы , Наследование для конкретной таблицы и Наследование для таблицы классов .

См. Классическую книгу Мартина Фаулера Шаблоны архитектуры корпоративных приложений для получения дополнительной информации о них.

Чтобы убедиться, что только один подтип может ссылаться на супертип, вы можете использовать поле ItemType. Внешний ключ может ссылаться на столбцы ограничения UNIQUE, а также на ПЕРВИЧНЫЙ КЛЮЧ. Таким образом, вы можете добавить Items.ItemType и наложить уникальное ограничение на ItemID, ItemType. Внешний ключ в каждой таблице подтипов ссылается на этот уникальный ключ из двух столбцов. И тогда вы можете ограничить ItemType в каждой таблице подтипов определенным значением. Затем оно должно соответствовать значению в таблице супертипов, которое может иметь только одно значение.

Items Table: ItemID (PK), ItemType, Name, Size
  UNIQUE: (ItemID, ItemType)
Widgets Table: ItemID (PK), ItemType, Color
  FK: (ItemID, ItemType)
  CHECK: ItemType=W
Doohicky Table: ItemID (PK), ItemType, Smell
  FK: (ItemID, ItemType)
  CHECK: ItemType=D
0 голосов
/ 09 сентября 2010

Если вы разрабатываете с учетом текущих классов, я бы предпочел ваш вариант 3 в качестве предпочтительного варианта по причинам, указанным выше.

Ваш запрос о:

However, I'm not sure how to create the relationship between the Items table and the
Widgets and Doohickies tables. I don't want to end up with row in either table 
referencing the same ItemID in the Items table. 

Предложение Билла выше, безусловно, хороший вариант. Что-то, о чем я не думал :-) Однако я подумал, что это отношение, которое вы можете применить либо в самом коде приложения, либо с помощью триггера вставки.

Однако меня беспокоит попытка смоделировать само наследование на уровне БД.

Если ожидается, что число дочерних классов будет расти в течение определенного периода времени, такой тип разработки БД может стать очень сложным для обслуживания.

В дополнение к:

Items Table: ItemID (PK), Name, Size        
Widgets Table: WidgetID (PK), ItemID (FK), Color        
Doohicky Table: DoohickyID (PK), ItemID (FK), Smell        

Какова вероятность добавления новых классов, таких как следующие?

DontDoHicky Table : DoohickyID (PK), ItemID (FK), Smell, **TASTE**        
MidWidget Table : WidgetID (PK), ItemID (FK), Color , **Height**        
MidDoHicky Table : WidgetID (PK), ItemID (FK), **Height**, **Smell**

Это, конечно, классическая проблема наследования ОО. Если вы ожидаете, что приложение будет расти таким образом в течение определенного периода времени, и, возможно, вам необходимо запланировать это заранее, на уровне БД, вы можете предпочесть использовать более общий подход

Items Table: ItemID (PK), Name, Size, **ItemType**        
**ItemAttributes Table : ItemID (PK), AttributeID, AttributeName, AttributeValue**    

Это позволит вам легко применить ограничение 1: 1 и легко запросить все атрибуты, используя AttributeName, если они являются стандартными.

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

0 голосов
/ 09 сентября 2010

Рассматривали ли вы решение NoSQL , например RavenDB или MongoDB ? Если ваши потребности не являются чисто реляционными, нереляционное решение может значительно упростить ситуацию.

...