Дизайн базы данных для маркировки нескольких типов объектов - PullRequest
5 голосов
/ 19 ноября 2008

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

Я думал о создании одной таблицы, которая имеет уникальный идентификатор, к которому относятся все сущности, и отношение n: m между таблицей тегов и таблицей «уникальный идентификатор». Таким образом, между таблицей «уникальный идентификатор» и таблицей тегов есть только одна кросс-таблица.

На всякий случай, если некоторые люди подумают, что этот вопрос уже задавался. Я уже прочитал Дизайн базы данных для тегов . И там упоминается дизайн трех столов.

Ответы [ 6 ]

2 голосов
/ 19 ноября 2008

Я бы сказал, это зависит от того, как вы хотите использовать теги.

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

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

CREATE TABLE Recipes (
  recipe_id INT NOT NULL PRIMARY KEY, -- not auto-generated
  FOREIGN KEY (recipe_id) REFERENCES Taggables(id)
);

Единственная слабость этого плана в том, что вы не можете помешать строке в Recipes и Ingredients указывать на одну и ту же строку в Taggables.

INSERT INTO Taggables (id) VALUES (327);
INSERT INTO Recipes (recipe_id, name) VALUES (327, 'Hollandaise sauce');
INSERT INTO Ingredients (ingr_id, name) VALUES (327, 'eggs');

Хотите, чтобы каждый тег, связанный с яйцами, также применялся к голландскому соусу?

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

2 голосов
/ 19 ноября 2008

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

Однако, одна важная деталь в вашем дизайне остается для меня двусмысленной: если вы собираетесь что-то делать в этом направлении

- - - - - - - - - -
Tag
    ID           // PK
    Name
    ...

- - - - - - - - - -
Taggable
    ID           // PK
    ...

- - - - - - - - - -
TagAssignment
    Tag_ID       // FK -> Tag.ID
    Taggable_ID  // FK -> Taggable.ID
    ...

- - - - - - - - - -
EntityOne
    Taggable_ID  // FK -> Taggable.ID
    ...

- - - - - - - - - -
EntityTwo
    Taggable_ID  // FK -> Taggable.ID
    ...

тогда ваши классы сущностей будут иметь свои собственные первичные ключи или вы собираетесь использовать EntityOne.TaggableID и EntityTwo.TaggableID в качестве фактических первичных ключей для EntityOne и EntityTwo?

В большинстве случаев я буду осторожен, и у сущностей будут свои идентификаторы:

- - - - - - - - - -
EntityOne
    ID           // PK
    Taggable_ID  // FK -> Taggable.ID (Nullable)
    ...

- - - - - - - - - -
EntityTwo
    ID           // PK
    Taggable_ID  // FK -> Taggable.ID (Nullable)
    ...

Для этого не требуется, чтобы у каждого объекта был соответствующий экземпляр Taggable, и, следовательно, для этого не требуется, чтобы каждый фрагмент кода, связанный с объектом, также знал о тегах. Однако, если пометка будет действительно повсеместно распространена в системе, и если вы уверены, что вам не понадобятся никакие другие «общие предки» для сущностей (то есть, кроме Taggable), то вы можете обойтись без «внутренние» идентификаторы для сущностей.

NB : Я никогда не пытался реализовать что-либо подобное, поэтому все мои рекомендации носят чисто теоретический характер. Поэтому, пожалуйста, не стреляйте в меня, если я не вижу каких-либо очевидных недостатков. : -)


В ответ на комментарий Билла Карвина:

Вы правы: описанный выше дизайн не мешает нескольким объектам ссылаться на один и тот же Taggable. Но:

  1. Как я уже сказал, все зависит от требований. Если мы уверены, что Taggable будет единственным «общим предком» сущностей, то можно использовать Taggable_ID FK в качестве PK для сущностей. Но, например, что, если некоторые объекты, которые оказываются «тегируемыми», также должны быть «наблюдаемыми» (например, уведомления, расписания уведомлений и т. Д.) Или «какими-либо способными» :-)? Можем ли мы обрезать все эти «способности», привязав любую сущность к Taggable?

  2. Если вы действительно хотите, чтобы на уровне БД применялось ограничение одного тега к одному объекту ... AFAIK, существует по крайней мере один общий способ сделать это, не заставляя FK служить в качестве PK: вводя " типы "taggables (которые могут быть полезны для некоторых других функций в любом случае).

Что-то вроде этого позволило бы нам съесть пирог и съесть его:

- - - - - - - - - -
Taggable
    ID           // PK
    Type        
    ... 
    - - - - - - - -
    Constraint: (ID, Type) is unique


- - - - - - - - - -
EntityOne
    ID
    Taggable_ID   
    Taggable_Type // Constraint: always = 'EntityOne'
    ...
    - - - - - - - -
    FK: (Taggable_ID, Taggable_Type) -> (Taggable.ID, Taggable.Type)

Конечно, все это сложнее, чем просто привязка сущностей к теговым тегам. Но я просто пытался обсудить, что, по моему скромному мнению, следует рассматривать в дополнение к узкой картине, представленной в первоначальном вопросе.

1 голос
/ 19 ноября 2008

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

Entity

  • EntityId
  • Имя

Ингредиент

  • EntityId
  • Сумма

RecipeIssuer

  • EntityId
  • SomeOtherInformation

Теперь вы можете иметь таблицу для пометки сущностей.

0 голосов
/ 15 февраля 2009

У меня тоже похожая «проблема» на руках. Я разрабатываю небольшую базу данных продуктов, которая включает тегирование, а также присваивает тегам значение (например, tagname: color, value: green).

Две основные таблицы - это позиции (I) и статьи (A). Предметы - это реальные физические предметы, а предметы извлекаются из предметов. Статьи - это то, что может отображаться на веб-сайте, а предметы - те, которые хранятся на складе. Небольшим примером таких отношений могут быть автомобильные запчасти. Радиатор с известными размерами и другими данными может на самом деле соответствовать многим различным моделям и маркам, поэтому элемент, используемый для повторного представления радиатора, относится к нескольким изделиям, которые указывают, что радиатор может соответствовать. С другой стороны, у нас может быть два разных радиатора для одной модели, одна из которых - заводская версия, а другая - только что восстановленная. В таком случае есть два пункта, относящиеся к одной и той же статье.

Итак, у меня и А отношения N: M.

Предметы и статьи имеют определенные свойства. Например, элемент радиатора может иметь такие данные, как состояние, материал, вес, высота, ширина и толщина. В статье также содержится некоторая базовая информация, такая как марка, модель, год выпуска, двигатель и т. Д., Но могут также потребоваться некоторые специальные данные, такие как модель шасси, тип трансмиссии или что-то еще, например два разных типа фитингов, которые использовались на одной и той же модели. Поскольку два элемента могут ссылаться на одну статью, это означает, что я не могу просто помечать статьи. Маркировать статью обоими значениями условия просто глупо, с другой стороны, маркировка одного элемента несколькими экземплярами модели, марки или какого-либо специального требования также не является хорошей идеей. _существуют два типа свойств: первый указывает на что-то, а второй - на то, что он подходит.

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

Радиаторы являются лишь примером простого продукта. Мы могли бы также поместить некоторые части компьютера или одежду в нашу базу данных. Это означает, что мне нужно иметь возможность размещать разные «теги» на двух разных объектах, I и A.

Мне нужно иметь возможность осуществлять поиск статей в интернет-магазине. Допустим, я использую древовидную навигацию, где у меня есть категория «Используемые радиаторы Nissan». Поиск будет включать в себя поиск как статей, так и предметов, статьи имеют тег Model: Nissan, а товары имеют тег Condition: Used. Конечно, когда пользователь просматривает статью, он действительно видит все элементы, связанные со статьей.

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

У нас есть элементы таблицы (I), статьи (A) и теги (T) Они соединены отношениями N: M: I2A присоединяет предметы к статьям. T2I присоединяет теги к элементам и может также хранить значение для тега или свойства. T2A присоединяет теги к статьям и может также хранить значение для тега.

На бумаге этот 6-табличный дизайн для решения этой проблемы выглядит довольно хорошо, но у меня болит голова при формировании достойного запроса, где я могу выбрать статьи, которые соответствуют набору различных тегов и их значениям, например: Состояние = Восстановленное, Марка = Nissan

То, что я хочу сделать, это что-то вроде www.summitracing.com. Выберите Отделы слева внизу «Магазин», выберите любую категорию, и вы увидите, как им удалось придать элементам некоторые свойства. У них есть размер двигателя для большинства применений, но при поиске ободов у них также есть свойство для ширины.

Буду признателен за любые отзывы по этому поводу, я начинаю бить мертвецов, пытаясь спроектировать это.

0 голосов
/ 19 ноября 2008

сделать таблицы как обычно для рецептов, ингредиентов и т. Д.

тогда ваша таблица тегов должна выглядеть так: Id, Type, Tag

Я бы рекомендовал использовать перечисление в коде, чтобы различать различные "типы" (сущности).

0 голосов
/ 19 ноября 2008

Как насчет этого?

Типы (PK: Тип , set_id [, TypeDesc])

Атрибуты (PK: ( set_id , FK: Тип ), Значение)

PS: Полужирный / Курсив Realy Suck

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