Мне нужно реализовать ключевые слова в приложении MVC, используемом для хранения линий животных (мы разрабатываем сначала базу данных). Каждое ключевое слово имеет отношение M: N к линиям животных.

Проблема в том, что у каждого ключевого слова есть множество синонимов и альтернативных вариантов написания. Итак, если линия животных особенно интересна иммунологам, она может получить ключевое слово T-Cells. Но заинтересованные стороны хотят, чтобы строку можно было найти, когда пользователи вводят t-cell, t cell, t Zelle или lymphocyte.

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

enter image description here

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

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

Я могу придумать три способа сделать это, но у всех трех есть недостатки:

  1. Включите бит isCanonicalSpelling в таблицу KeywordSpelling. Легко, но если в моем коде есть ошибка или кто-то напишет быстрый сценарий, чтобы что-то сделать с базой данных, я могу оказаться в ситуации, когда более или менее одного написания одного и того же ключевого слова помечено как каноническое.
  2. Включите поле canonicalSpelling в таблицу ключевых слов. В этом случае каноническое правописание не будет записано в таблицу правописания. По-прежнему относительно легко, но почему-то кажется нечистым иметь варианты написания, которых нет в таблице правописания. Код для замены канонического и неканонического написания более сложен.
  3. Установите второе соотношение 1: 1 между таблицей Keyword и KeywordSpelling. С точки зрения ERD, это кажется лучшим решением, но я не уверен, как обеспечить его соблюдение с помощью инструментов, которые я использую. Я не знаю, допускает ли сервер Microsoft SQL хотя бы отношения 1: 1, и даже если это так, я не знаю, что мне нужно сделать, чтобы Entity Framework хорошо играла, это, вероятно, потребует большого количества кода.

Итак, какое решение вы бы назвали лучшим? Какой из них вызовет у меня наименьшую головную боль в будущем и почему? Есть ли недостатки у любого из решений, которые я упустил? Есть ли еще лучшее решение, о котором я не думал?

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

1
Rumi P. 2 Янв 2014 в 19:24

2 ответа

Лучший ответ

Я бы выбрал вариант 3 в сочетании с естественными ключами:

CREATE TABLE Keyword (
    ID INT PRIMARY KEY,
    CanonicalSpelling VARCHAR(100)
);

CREATE TABLE KeywordSpelling (
    ID INT,
    Spelling VARCHAR(100),
    PRIMARY KEY (ID, Spelling)
);

ALTER TABLE Keyword
    ADD FOREIGN KEY (ID, CanonicalSpelling)
    REFERENCES KeywordSpelling (ID, Spelling);

INSERT INTO Keyword VALUES (1, NULL);

INSERT INTO KeywordSpelling VALUES (1, 'T-Cells');
INSERT INTO KeywordSpelling VALUES (1, 't-cell');
INSERT INTO KeywordSpelling VALUES (1, 't cell');
INSERT INTO KeywordSpelling VALUES (1, 't Zelle');
INSERT INTO KeywordSpelling VALUES (1, 'lymphocyte');

UPDATE Keyword SET CanonicalSpelling = 'T-Cells' WHERE ID = 1;

Обратите внимание, что поле CanonicalSpelling является копией значения, которое уже существует в таблице KeywordSpelling. Это отличается от варианта 2, у которого просто будет независимое значение.

На первый взгляд копия может показаться излишней, но имейте в виду, что СУБД всегда будет предохранять ее от «зависания» из-за FK.

  • Таким образом, вы можете продолжать опрашивать таблицу KeywordSpelling обычным способом и быть уверенными, что она содержит все значения, включая канонические.
  • OTOH, если вам просто нужно каноническое значение, вам даже не нужно обращаться к KeywordSpelling.

вариант 2 потребует специальной обработки канонического значения - вам нужно будет запросить как Keyword, так и KeywordSpelling, чтобы получить все значения, и вы не можете полагаться на СУБД для обеспечения уникальности таблиц.

Для варианта 1 потребуется индекс по {ID, IsCanonical} (в таблице KeywordSpelling). К счастью, MS SQL Server поддерживает отфильтрованные индексы, поэтому влияние будет значительным. меньше индекса во всех строках. Поскольку MS SQL Server в любом случае не может обеспечить истинное значение 1: 1 (см. Ниже), это действительно жизнеспособное решение, но вариант 3 по-прежнему позволяет получить каноническое значение без доступа к таблице правописания вообще.


Приведенная выше структура допускает отсутствие канонического значения (CanonicalSpelling поддерживает NULL). Другими словами, это соотношение 1: 0..1.

В СУБД, которая поддерживает отложенные ограничения (к сожалению, MS SQL Server не поддерживает), вы можете декларативно обеспечить реальное соотношение 1: 1 следующим образом:

CREATE TABLE Keyword (
    ID INT PRIMARY KEY,
    CanonicalSpelling VARCHAR(100) NOT NULL
);

CREATE TABLE KeywordSpelling (
    ID INT,
    Spelling VARCHAR(100),
    PRIMARY KEY (ID, Spelling)
);

ALTER TABLE Keyword
    ADD FOREIGN KEY (ID, CanonicalSpelling)
    REFERENCES KeywordSpelling (ID, Spelling)
    DEFERRABLE INITIALLY DEFERRED;

INSERT INTO Keyword VALUES (1, 'T-Cells');

INSERT INTO KeywordSpelling VALUES (1, 'T-Cells');
INSERT INTO KeywordSpelling VALUES (1, 't-cell');
INSERT INTO KeywordSpelling VALUES (1, 't cell');
INSERT INTO KeywordSpelling VALUES (1, 't Zelle');
INSERT INTO KeywordSpelling VALUES (1, 'lymphocyte');
1
Branko Dimitrijevic 3 Янв 2014 в 02:46

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

Я не знаю ни одного решения по умолчанию, но могу предложить довольно много вариантов:

  • Будет ли всегда один «главный» синоним? Ни меньше, ни больше? Я бы предложил добавить столбец (nvarchar) к элементам Keyword, где вы вводите правильное написание. Если пользователь затем использует синоним, вы можете легко получить доступ к чему-то вроде SynonymEntity.ParentKeyword.Name. ( Если это помогает алгоритму поиска синонимов, вы все равно можете добавить запись синонима ниже с тем же самым словом. Немного больше данных для хранения, но тогда вы можете легко перебирать список при сопоставлении всех возможных значений. < / em>)

  • Возможно ли когда-либо НЕ установить правильное имя? Или несколько? (например, американский / британский английский) В этом сценарии я бы выбрал дополнительный столбец в таблице синонимов, чтобы поместить логическое значение (IsCorrectSpelling). В случае, если у вас их несколько, возникает необходимость либо найти правильный язык для выбранного языка (например, второй столбец для определения настроек культуры). Или вы можете просто использовать MultipleSynonyms.FirstorDefault(word => word.IsCorrectSpelling).

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

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

1
Flater 2 Янв 2014 в 16:51