Что такое шаблоны проектирования для поддержки пользовательских полей в приложении? - PullRequest
70 голосов
/ 14 июля 2009

Разрабатываем коммерческое приложение.Наши клиенты просят о поддержке пользовательских полей.Например, они хотят добавить поле в форму Заказчика.

Каковы известные шаблоны проектирования для хранения значений полей и метаданных о полях?

Я вижу эти параметрына данный момент:

Опция 1 : Добавить столбцы Field1, Field2, Field3, Field4 типа varchar в мою таблицу Customer.

Опция 2 :Добавьте один столбец типа XML в таблицу customer и сохраните значения настраиваемых полей в формате xml.

Option 3 : добавьте таблицу CustomerCustomFieldValue со столбцом типа varchar и сохраните значения вэтот столбец.Эта таблица также будет иметь CustomerID, CustomFieldID.

CustomerID,  CustomFieldID, Value
10001,       1001,          '02/12/2009 8:00 AM'
10001,       1002,          '18.26'
10002,       1001,          '01/12/2009 8:00 AM'
10002,       1002,          '50.26'

CustomFieldID будет идентификатором из другой таблицы с именем CustomField со следующими столбцами: CustomFieldID, FieldName, FieldValueTypeID.

Option4 : добавьте таблицу CustomerCustomFieldValue со столбцом каждого возможного типа значения и сохраните значения в правом столбце.Аналогично # 3, но значения полей хранятся в столбце строгого типа.

CustomerID,  CustomFieldID, DateValue,           StringValue,       NumericValue                 
10001,       1001,          02/12/2009 8:00 AM,  null,              null
10001,       1002,          null,                null,              18.26
10002,       1001,          01/12/2009 8:00 AM,  null,              null
10002,       1002,          null,                null,              50.26

Опция 5 : в опциях 3 и 4 используется таблица, относящаяся к одному концепту (Клиент).Наши клиенты просят настраиваемое поле и в других формах.Должны ли мы вместо этого иметь общесистемную систему хранения пользовательских полей?Таким образом, вместо нескольких таблиц, таких как CustomerCustomFieldValue, EmployeeCustomFieldValue, InvoiceCustomFieldValue, у нас будет одна таблица с именем CustomFieldValue?Хотя это кажется мне более элегантным, не вызовет ли это узкое место в производительности?

Использовали ли вы какой-либо из этих подходов?Вы были успешны?Какой подход вы бы выбрали?Знаете ли вы какой-либо другой подход, который я должен рассмотреть?

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

Спасибо

======================

РЕДАКТИРОВАТЬ 07-27-2009:

Спасибо за ваши ответы.Похоже, что список подходов сейчас довольно полный.Я выбрал вариант 2 (один столбец XML).Это было проще всего реализовать на данный момент.Вероятно, мне придется отказаться от более строго определенного подхода, поскольку мои требования будут усложняться, а количество поддерживаемых настраиваемых полей будет увеличиваться.

Ответы [ 7 ]

14 голосов
/ 14 июля 2009

Я согласен с постерами ниже, что варианты 3, 4 или 5, скорее всего, будут уместными. Однако каждая из предложенных вами реализаций имеет свои преимущества и затраты. Я бы предложил выбрать один, сопоставив его с вашими конкретными требованиями. Например:

  1. Плюсы 1 варианта: Быстрая реализация. Разрешает действия БД над пользовательскими полями (поиск, сортировка.)
    Вариант 1 минусы: настраиваемые поля являются общими, поэтому нет строго типизированных полей. Таблица базы данных является неэффективной по размеру со многими посторонними полями, которые никогда не будут использоваться. Количество допустимых настраиваемых полей должно быть ожидаемым.
  2. Плюсы 2 варианта: Быстрая реализация. Гибкость, допускающая произвольное количество и тип настраиваемых полей.
    Вариант 2 минусы: Действия с БД невозможны для пользовательских полей. Лучше всего, если все, что вам нужно сделать, это отобразить настраиваемые поля позже или выполнить незначительные манипуляции с данными только для каждого клиента.
  3. Плюсы 3 варианта: и гибкие, и эффективные. Действия БД могут быть выполнены, но данные несколько нормализованы, чтобы уменьшить потерянное пространство. Я согласен с неизвестным (Google) предложением добавить дополнительный столбец, который можно использовать для указания типа или источника информации. Варианты 3: небольшое увеличение времени разработки и сложности ваших запросов, но здесь действительно не так много минусов.
  4. Опция 4 такая же, как и Опция 3, за исключением того, что ваши введенные данные могут обрабатываться на уровне БД. Добавление информации о типе в таблицу ссылок в варианте 3 позволяет вам выполнять больше операций на уровне нашего приложения, но, например, БД не сможет выполнять сравнения или сортировку. Выбор между 3 и 4 зависит от этого требования.
  5. Вариант 5 такой же, как 3 или 4, но с еще большей гибкостью, чтобы применять решение для множества различных таблиц. Стоимость в этом случае будет состоять в том, что размер этой таблицы будет расти намного больше. Если вы выполняете много дорогостоящих операций объединения, чтобы добраться до своих пользовательских полей, это решение может плохо масштабироваться.

P.S. Как отмечено ниже, термин «шаблон проектирования» обычно относится к объектно-ориентированному программированию. Вы ищете решение проблемы проектирования базы данных, а это означает, что большинство советов относительно шаблонов проектирования не будут применимы.

10 голосов
/ 14 июля 2009

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

Согласно приведенным ниже комментариям, самая значительная ошибка, которую вы можете совершить с этой моделью, заключается в добавлении в нее внешних ключей. Никогда не помещайте что-то вроде FriendID или TypeID в эту модель. Используйте эту модель в сочетании с типичной реляционной моделью и сохраняйте поля внешнего ключа в столбцах таблицы, как они должны.

Вторая существенная ошибка заключается в размещении данных в этой модели, которые необходимо сообщать с каждым элементом. Например, если ввести в эту модель что-то вроде имени пользователя, это будет означать, что в любое время, когда вы хотите получить доступ к пользователю и вам нужно знать его имя пользователя, вы в лучшем случае обязуетесь присоединиться к нему или 2n запросов, где n - это количество пользователей, на которое вы просматриваете , Если вы считаете, что вам обычно требуется свойство Username для каждого элемента User, становится очевидно, что это также должно остаться в столбцах таблицы.

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

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

4 голосов
/ 14 июля 2009

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

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

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

Создание хорошего AOM с работающим хранилищем данных для него - большая работа, и я не рекомендовал бы его, если у вас нет высококвалифицированных разработчиков. Возможно, однажды будет решение для ОС для таких требований.

Пользовательские поля обсуждались ранее в SO:

3 голосов
/ 14 июля 2009

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

Некоторые мысли:

  • Убедитесь, что у вашего CustomFields есть столбец DataType.
    • Используйте проверочное ограничение на основе UDF для CustomFieldValues, чтобы убедиться, что столбец, указанный в CustomFields.DataType, не равен нулю.
    • Вам также потребуется стандартное проверочное ограничение, чтобы убедиться, что у вас есть только одно ненулевое значение.
  • Что касается внешних ключей, я бы смоделировал их как отдельные DataType.
    • Для каждой потенциальной ссылки на перекрестную таблицу потребуется собственный столбец. Это хорошо, потому что поддерживает ссылочную целостность.
    • В любом случае вам придется поддерживать эти отношения в коде приложения, поэтому тот факт, что они жестко запрограммированы в базе данных, фактически не ограничивает функциональность.
    • Это также хорошо сочетается с вашим ORM, если вы его используете.
  • Для варианта 5 используйте промежуточные таблицы для моделирования отношений.
    • Вы бы все равно имели CustomerCustomFieldValue, но вместо этого только с CustomerID и CustomFieldValueID столбцами.
  • Долго и усердно думайте о своих ограничениях на каждом этапе пути. Это сложная штука, и один неверный шаг может вызвать полный хаос.

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

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

3 голосов
/ 14 июля 2009

Что-то вроде варианта 3 - это путь, и я использовал этот метод ранее. Создайте единую таблицу для определения дополнительных свойств и их соответствующих значений. Это будет отношение 1-N между таблицей Customer и CustomerCustomField (соответственно). Ваш второй вопрос, касающийся определения отношений с пользовательскими свойствами, будет о чем подумать. Первое, что приходит на ум, - это добавление поля DataSource, которое будет содержать таблицу, к которой привязано значение свойства. По сути, ваш CustomerCustomField будет выглядеть так:

  1. CustomerId
  2. Недвижимость
  3. Значение
  4. ValueDataSource (обнуляемый)

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

0 голосов
/ 26 мая 2017

В настоящее время я работаю над проектом с этой же проблемой, и я решил использовать вариант 3, но я добавил поле FieldType и поле ListSource в случае FieldType = "list". Поле ListSource может быть запросом, представлением sql, именем функции или чем-то, что приводит к списку опций для списка. Самая большая проблема при попытке сохранить такие поля в моей ситуации заключается в том, что этот список полей может измениться, и пользователям разрешено редактировать данные позже. Так что же делать, если список полей изменился и они идут на редактирование. Мое решение этого сценария состояло в том, чтобы разрешить редактирование, только если список не изменился, и отображать данные только для чтения, если оно имело.

0 голосов
/ 14 июля 2009

если эти «дополнительные» поля являются случайными и не хотят выполнять поиск по ним, я обычно выбираю вариант 2 (но лучше JSON, чем XML). Если будет поиск по пользовательским полям, вариант 3 не составит труда, и обычно оптимизатор SQL может получить из этого разумную производительность.

...