Пользовательские поля для формы, представляющей объект - PullRequest
5 голосов
/ 13 сентября 2011

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

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

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

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

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

Я думал о таблице UserConfiguration, где каждая запись имеет внешний ключ для клиента (канал в нашей базе данных), затем столбец FieldName, столбец FieldTypeи столбец Значения.Значения столбца должны быть столбцом типа xml, потому что для раскрывающегося списка нам нужно добавить несколько значений.Кроме того, к каждому значению могут быть прикреплены дополнительные данные (а не только имя).Другая проблема заключается в том, как сохранить выбранное значение.Мне не нравится идея иметь внешние ключи для xml в моей базе данных (читайте где-нибудь, что Azure не может справиться со всем этим хорошо).Вы просто сохраняете имя значения (что, если значение исчезнет из xml?)?

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

Ответы [ 4 ]

4 голосов
/ 23 сентября 2011

Я хочу ответить на ваш вопрос в двух частях:
1) Реализация пользовательских полей на сервере базы данных
2) Ограничение пользовательских полей перечислением значений


Хотя общие решения 1) обсуждаются в вопросе , на который ссылается @Simon, возможно, вы ищете небольшую дискуссию о том, в чем заключается проблема и почему она еще не решена для нас .

  • базы данных отлично подходят для структурированных типизированных данных
  • пользовательские поля по своей природе менее структурированы
  • поэтому с пользовательскими полями сложнее работать в базе данных
  • некоторые или многие преимущества использования базы данных потеряны
    • некоторые запросы могут быть более сложными или невозможными
    • Безопасность типа может быть потеряна (в базе данных)
    • целостность данных больше не может быть обеспечена (база данных)
    • это гораздо больше работы для разработчиков и сопровождающих

Как обсуждалось в другом вопросе , идеального решения не существует.
Но эти преимущества / функции все еще необходимо где-то реализовать, и поэтому приложение часто отвечает за целостность данных и безопасность типов.
Для подобных ситуаций люди создали Инструменты сопоставления объектных отношений , хотя, как говорит Джефф Этвуд , , даже использование ORM может создать больше проблем, чем решит. Тем не менее, вы упомянули, что он «должен быть общим и иметь возможность решать все виды проблем в будущем» - это заставляет меня думать, что ORM может быть вашим лучшим выбором.

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


Чтобы ответить на вторую часть (я думаю, что) вашего вопроса:
Как упоминалось в связанном вопросе, вы можете внедрить Entity-Attribute-Value в своей базе данных для настраиваемых полей, а затем добавить дополнительную таблицу для хранения допустимых значений для каждой сущности. Затем атрибут / значение таблицы EAV является внешним ключом в таблице значений атрибутов.

Например,

CREATE TABLE `attribute_value` ( -- enumerations go in this table
    `attribute` varchar(30), 
    `value` varchar(30), 
    PRIMARY KEY (`attribute`, `value`)
);

CREATE TABLE `eav` ( -- now the values of attributes are restricted
    `entityid` int, 
    `attribute` varchar(30), 
    `value` varchar(30), 
    PRIMARY KEY (`entityid`, `attribute`), 
    FOREIGN KEY (`attribute`, `value`) REFERENCES `attribute_value`(`attribute`, `value`)
);

Конечно, это решение не является идеальным или полным - оно только должно проиллюстрировать идею. Например, он использует varchars и не имеет столбца type. Кроме того, кто решает, каковы возможные значения для каждого атрибута? Могут ли они быть изменены пользователем в любое время?

2 голосов
/ 26 сентября 2011

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

Я думаю, что ваш подход к таблице UserConfiguration хорош и будет предлагать толькоабстрагирование частей «type» и «value» в вашем дизайне немного подробнее:

  • Поскольку вашему приложению потребуется проверять вводимые пользователем данные, каждое понятие «type» будет иметь связанную частьоценки логики.Очевидно, что чем больше вы можете абстрагироваться в данные, тем легче будет сохранить ваш код небольшим.Перечисляемые списки являются хорошим началом, но если ваша логика «валидатора» может быть расширена для обработки сопоставления с образцом для текстовых строк и логических выражений (например, для описания / применения ограничений на входные значения), то вы можете выразить практически любой «тип»входных данных, которые могут понадобиться вашему приложению в терминах (относительно) простых «атомов», которые вы можете естественным образом отобразить в таблицы БД.

  • При сохранении указанного пользователем значения вы можетелибо сохраните «сырые» данные (например, в JSON) и внешний ключ к связанному «типу», либо вы можете добавить систему поиска / кэширования, которая присваивает целое число каждому новому значению, с которым сталкивается система («новизна»)например, можно проверить, проверив хеш «необработанных» данных).Последний подход, очевидно, лучше масштабируется, если вы ожидаете много дублирования данных (что, конечно, вы бы сделали в случае меню с множественным выбором).

2 голосов
/ 23 сентября 2011

Когда вы разрешаете пользователям создавать модели данных, я бы рекомендовал просмотреть базу данных документов или «NoSQL», поскольку вы хотите именно это, чтобы хранить структуры данных без схемы.

Кроме того, sharePoint хранит метаданные так, как вы упомянули (10 столбцов для текста, 5 для дат и т. Д.)

Тем не менее, в моем текущем проекте (заблокирован в SharePoint, поэтому Framework 3.5 + SQL Server и все последующие ограничения) мы используем несколько похожую структуру, как показано ниже:

Form
 Id

Attribute (or Field)
 Name
 Type (enum) Text, List, Dates, Formulas etc
 Hidden (bool)
 Mandatory
 DefaultValue
 Options (for lists)
 Readonly
 Mask (for SSN etc)
 Length (for text fields)
 Order

Metadata
 FormId
 AttributeId
 Text (the value for everything but dates)
 Date (the value for dates)

В наших формулах используются такие функции, как Increment: INC([attribute1][attribute2], 6), и это выдает что-то вроде 000999 для 999-го экземпляра объединенных значений для атрибута 1 и атрибута 2 для формы, это сохраняется как:

AttributeIncrementFormula
 AtributeId
 Counter
 Token

Другие «формулы» (иначе нетривиальные), такие как штрих-коды, хранятся в виде отдельных значений метаданных. В реальной реализации у нас будет что-то вроде этого:

var form = formRepository.GetById(1);
form.Metadata["firstname"].Value

Значение выше - это свойство только для чтения, которое решает, следует ли нам получать значение из Text или Date и требуется ли какое-либо дополнительное преобразование. Обратите внимание, что база данных здесь просто хранилище, мы храним всю сложность домена в приложении.

Мы также позволяем нашему клиенту решить, какой атрибут, например, является заголовком формы, поэтому, если firstname является заголовком формы, они установят параметр в памяти, который охватывает все приложение, как что-то вроде Params.InMemory.TitleAttributeId = <user-defined-id>.

Надеюсь, это даст вам некоторое представление о сценарии аналогичного сценария.

2 голосов
/ 23 сентября 2011

Я делаю что-то подобное для клиента. Я создал JSON FieldType, который содержит весь поток JSON сложного объекта и строку, содержащую FQTN (FullQualifiedTypeName) моего класса модели C #.

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

Чтобы продвигать поля из сложной модели C # в список SharePoint, мы создали нечто подобное, что Microsoft сделала в InfoPath. Пользователи могут выбирать свойства или метаданные из типа Complex C #, которые будут автоматически добавлены в список хостинга SharePoint.

Большим преимуществом JSON является то, что он меньше, чем XML, и с ним легче работать в веб-мире. (JavaScript ...)

...