2011-09-13 27 views
5

Tengo una pregunta de arquitectura sobre campos personalizados en una vista para un objeto. Supongamos que tiene un objeto de usuario con información básica como firstname, lastname, ... que pueden usar todos los clientes.Campos personalizados para un formulario que representa un objeto

Ahora, a menudo recibimos una pregunta de un cliente para agregar un par de campos personalizados típicos de su dominio. Nuestra solución ahora es una columna de datos xml donde se almacenan los pares clave de valores. Esto ha estado bien hasta ahora, pero ahora tendremos que encontrar una solución más arquitectónica.

Por ejemplo, ahora, un cliente desea un menú desplegable donde puede seleccionar el valor para su campo personalizado. Todavía podríamos almacenar el valor seleccionado en la columna de datos xml, pero ¿dónde almacenamos todos esos valores desplegables ...

Sé que en sharepoint también puede agregar campos personalizados como menús desplegables y me preguntaba cómo lidiar con esto mejor Quiero evitar crear tablas personalizadas para los clientes, o tener una tabla con 90 columnas (10 básicas y luego 10 para cada cliente), ...

Se entiende la idea, debe ser genérica y poder tratar con todo tipo de problemas en el futuro

Lo que estaba pensando es una configuración de usuario de tabla donde cada registro tiene una clave externa para el cliente (canal en nuestra base de datos), luego una columna FieldName, una columna FieldType y una columna Valores. Los valores de columna deben ser una columna de tipo xml, porque para un menú desplegable, necesitaremos agregar varios valores. Además, cada valor puede tener datos adicionales adjuntos (no solo un nombre). El otro problema es cómo almacenar el valor seleccionado. No me gusta la idea de tener claves externas a xml en mi base de datos (lea en alguna parte que Azure no puede manejar todo esto muy bien). ¿Simplemente almacena el nombre del valor (¿qué pasaría si el valor fuera a desaparecer del xml?)?

Cualquier documentación, enlaces sobre este tipo de problemas también sería genial. Estoy tratando de encontrar un patrón de diseño que trate este tipo de problema en la base de datos.

+0

Si esto no está relacionado con el tema, entonces usted no es un programador de la vida real. –

+1

¿Ha visto esto en SO: http://stackoverflow.com/questions/1126783/what-are-design-patterns-to-support-custom-fields-in-an-application? Parece bastante completo el tema. –

+0

@Simon Thx, aún no había encontrado ese. –

Respuesta

4

quiero responder a su pregunta en dos partes:
1) la aplicación de campos personalizados en un servidor de base de datos
2) La restricción de campos personalizados para una enumeración de valores


Aunque las soluciones comunes para 1) se tratan en el question al que hace referencia @Simon, tal vez esté buscando un poco de discusión sobre cuál es el problema y por qué no se ha resuelto para nosotros.

  • bases de datos son grandes estructurados, de los datos a máquina
  • campos personalizados son inherentemente menos estructurado
  • , por lo tanto, los campos personalizados son más difíciles de trabajar en una base de datos
  • algunas o muchas de las ventajas de utilizar una base de datos se pierden
    • algunas consultas pueden ser más difíciles o imposibles
    • seguridad de tipos puede perderse (en la base de datos)
    • integridad de los datos puede ser aplicada ya no (por la base de datos)
    • es mucho más trabajo para los ejecutores y mantenedores

Como se discutió en la other question, no hay una solución perfecta.
Pero estos beneficios/características aún deben implementarse en alguna parte, y con frecuencia la aplicación se vuelve responsable de la integridad de los datos y la seguridad del tipo.
Para situaciones como estas, las personas han creado Object-Relation Mapping tools, aunque, como Jeff Atwood says, incluso el uso de un ORM podría crear más problemas de los que resuelve. Sin embargo, mencionó que 'debería ser genérico y ser capaz de enfrentar todo tipo de problemas en el futuro' - esto me hace pensar que un ORM podría ser su mejor opción.

Por lo tanto, para resumir mi respuesta, este es un problema conocido con soluciones conocidas, ninguna de las cuales es completamente satisfactoria (porque es muy difícil). Elige tu veneno.


Para responder a la segunda parte de (lo que creo que es) a su pregunta:
Como se mencionó en la pregunta vinculada, se podría aplicar Entity-Attribute-Value en su base de datos para los campos personalizados, y luego añadir una mesa extra para mantener los valores legales para cada entidad. Entonces, el atributo/valor de la tabla EAV es una clave foránea en la tabla de valor de atributo.

Por ejemplo,

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`) 
); 

Por supuesto, esta solución no es perfecta o completa - que sólo supone para ilustrar la idea. Por ejemplo, utiliza varchars y carece de una columna type. Además, ¿quién decide cuáles son los valores posibles para cada atributo? ¿Pueden estos ser cambiados en cualquier momento por el usuario?

2

Estoy haciendo algo similar para un cliente. Creé un JSON FieldType que contiene toda la secuencia JSON de un objeto complejo y una cadena que contiene el FQTN (FullQualifiedTypeName) de mi clase de modelo C#.

Al utilizar New-, Edit- and Display-Forms personalizados nos aseguramos de que nuestros objetos personalizados se renderizaran de la manera correcta para una mejor experiencia del usuario.

Para promocionar campos del complejo modelo C# a la lista de SharePoint, hemos creado algo parecido a lo que hizo Microsoft en InfoPath. Los usuarios pueden seleccionar Propiedades o MetaData del tipo Complex C#, que se promocionará automáticamente a la lista de SharePoint de hosting.

La gran ventaja de JSON es que es más pequeña que XML y más fácil de usar en el mundo web. (JavaScript ...)

2

Cuando permite a los usuarios crear los modelos de datos, recomendaría buscar en una base de datos de documentos o 'NoSQL' ya que quiere exactamente eso, para almacenar estructuras de datos sin esquemas.

Además, las tiendas de SharePoint Metadatos Las modo que usted ha mencionado (10 columnas de texto, 5 para fechas, etc.)

Dicho esto, en mi proyecto actual (bloqueado en SharePoint, por lo que Marco 3.5 + SQL Server y todas las restricciones que siguen) que utilizamos una estructura algo similar a continuación:

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) 

Nuestras fórmulas emplean funciones tales como Incremento: INC([attribute1][attribute2], 6) y esto produciría algo así como 000.999 para la instancia número 999 de la combinada valores de atributo 1 y el atributo 2 para un formulario, este se almacena como:

AttributeIncrementFormula 
AtributeId 
Counter 
Token 

Other 'fórmulas' (también conocido como algo no trivial), tales como los códigos de barras se almacenan como valores de metadatos individuales. En la implementación actual, tendríamos algo como esto:

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

valor anterior es una propiedad de sólo lectura que decide si se debe obtener el valor de Texto o Fecha y si alguna transformación adicionales que se requiere. Tenga en cuenta que la base de datos aquí es simplemente un almacenamiento, tenemos toda la complejidad del dominio en la aplicación.

También dejamos que nuestro cliente decida qué atributo es el título del formulario, por ejemplo, si firstname es el título del formulario, establecerá un parámetro en memoria que abarca toda la aplicación para ser algo así como Params.InMemory.TitleAttributeId = <user-defined-id>.

Espero que esto le dé una idea de una implementación de producción de un escenario similar.

2

Esto es realmente más de un comentario que una respuesta, pero necesito más espacio que el SO permitirá comentarios, asi que aquí 'Tis:

Creo que su enfoque de tabla UserConfiguration es buena, y sugeriría única abstracción el "tipo" y piezas de "valor" de su diseño un poco más:

  • Debido a que su aplicación tendrá que validar la entrada del usuario, cada una noción de "tipo" tendrán una pieza asociada de la lógica de evaluación. Obviamente, mientras más de esto puedas abstraer en datos, más fácil será mantener tu código pequeño. Las listas enumeradas son un buen comienzo, pero si su lógica de "validador" puede ampliarse para manejar la coincidencia de patrones para cadenas de texto y expresiones lógicas booleanas (por ejemplo, para describir/imponer restricciones a los valores de entrada), puede expresar prácticamente cualquier "tipo" de entrada que su aplicación necesite manejar en términos de "átomos" (relativamente) simples que puede asignar de forma natural a las tablas de BD.

  • Al almacenar un valor especificado por el usuario, puede almacenar los datos "en bruto" (por ejemplo, en JSON) y una clave externa al "tipo" asociado, o puede agregar un sistema de búsqueda/caché que le asigne un entero para cada valor nuevo que encuentre el sistema (la "novedad" se puede verificar mediante la comprobación de un hash de los datos "en bruto", por ejemplo). El último enfoque, obviamente, se escala mejor si está esperando mucha duplicación de datos (que por supuesto lo haría en el caso de un menú de opción múltiple).

Cuestiones relacionadas