En términos generales, ¿se considera una mala práctica permitir campos creados por el usuario en una base de datos para una aplicación web?
Por ejemplo, estoy haciendo una aplicación web de inventario de viviendas para mi esposa, y ella querrá definir sus propios campos para diferentes artículos. Estaba planeando permitirle crear categorías de elementos y agregar "características" a esas categorías. Las características solo serían clave / valor almacenado como cadenas. De esa manera, si tuviera una categoría llamada "CD de audio", por ejemplo, podría agregar características para cosas como "artista", "pistas", etc. Pero en otra categoría como "muebles", podría agregar características para cosas como "material". "(madera, plástico, etc.). Entonces, cualquier elemento podría pertenecer a una (o muchas) categorías, agregando esas características al elemento.
Puedo ver problemas en los que la búsqueda por estas características requiere comparaciones de cadenas, no hay validación de datos, etc. Siguiendo una metodología ágil, tal vez sería mejor simplemente tener nuevas categorías y atributos y simplemente tendría que crear nuevas tablas a medida que avanzamos. En mi ejemplo, es una pequeña base de usuarios (2 de nosotros) y la cantidad de registros creados sería pequeña, por lo que no está tan mal.
Sin embargo, en términos generales, ¿cómo manejan las personas algo como esto en la "vida real"?
Respuestas:
Cuando comienza a acceder a "campos definidos por el usuario", como se encuentra a menudo en los rastreadores de errores, la gestión de recursos del cliente y herramientas comerciales similares, es que no están respaldados con una tabla con miles de millones de campos (si lo están, entonces es probable que sea un problema de su propio).
En cambio, lo que encuentra son los diseños de tabla de Valor de atributo de entidad y la herramienta de administración asociada para administrar los atributos válidos.
Considere la siguiente tabla:
Esto es después de haber agregado algunos atributos. En lugar de
attr1
pretender que leeartist
otracks
ogenre
o lo que sea atributos lo tiene. Y en lugar de 5, qué pasaría si fueran 50. Claramente eso es inmanejable. También requiere una actualización del modelo y la redistribución de la aplicación para manejar un nuevo campo. No es ideal.Ahora considere la siguiente estructura de tabla:
Tienes lo tuyo con sus campos básicos. Tienes dos mesas más. Uno con los atributos. Cada campo es una fila en la
attr
tabla. Y luego está elthing_attr
con un par de claves externas relacionadas con lathing
tabla y laattr
tabla. Y esto luego tiene un campo de valor donde se almacena el valor del campo para esa entidad.Y ahora tiene una estructura donde la tabla de atributos se puede actualizar en tiempo de ejecución y se pueden agregar (o eliminar) nuevos campos sobre la marcha sin un impacto significativo en la aplicación general.
Las consultas son un poco más complejas y la validación se vuelve más compleja también (ya sea procedimientos almacenados funky o todo el lado del cliente). Es una compensación en el diseño.
Considere también la situación en la que algún día necesita hacer una migración y vuelve a la aplicación para encontrar que ahora hay media docena más o menos de atributos que el esquema que distribuyó originalmente. Esto permite migraciones y actualizaciones feas donde la tabla de valores de atributo de entidad, cuando se usa correctamente, puede ser más limpia. (No siempre, pero puede ser).
Si está trabajando con el sabor apropiado de la base de datos nosql, probablemente podría hacer esto (tenga en cuenta que el sabor apropiado del nosql para esto probablemente sería un almacén de valores clave que es, bueno, la tabla EAV para los relacionales descritos anteriormente) sin demasiados problemas Sin embargo , viene con todos los compromisos para nosql que se describen en otra parte con gran detalle.
Si, en cambio, está trabajando en una base de datos relacional, debe tener el esquema. Agregar la columna dinámicamente significa que algunos subconjuntos de las siguientes cosas son verdaderas:
select *
y luego haciendo un código complejo para averiguar cuáles son realmente los datos (consulte ResultSetMetaData de Java ) y luego almacenarlos en un mapa ( o algún otro tipo de datos, pero no campos agradables en el código). Esto arroja un poco de seguridad tipográfica y tipográfica que tiene con el enfoque tradicional.hasdate
campo para almacenar una marca de tiempo ya se ha definido comohasdate
un booleano para una coincidencia exitosa ... y su actualización se rompe.varchar2
vstext
y similares. Su código para agregar la columna funcionaría en MySQL pero no en Postgres, Oracle o SQL Server.delete * from students
cambio, pero realmente no puede estropear la base de datos de manera incorrecta). La cantidad de cosas que pueden salir mal con el acceso al esquema, ya sea por accidente o por actividad maliciosa, se dispara.Esto realmente se reduce a "no lo hagas". Si realmente quiere esto, vaya con un patrón conocido de la estructura de la tabla EAV o una base de datos que esté completamente dedicada a esta estructura. No permita que las personas creen campos arbitrarios en una tabla. Los dolores de cabeza simplemente no valen la pena.
fuente
Hacer esto bien es difícil.
Para una aplicación única como la que está planeando, puede, por supuesto, agregar una columna para cada campo y proporcionar una interfaz de usuario que haga que la definición de campo por parte de usuarios no capacitados sea más segura que darles una línea de comando SQL. O puede seguir el temido patrón Entidad-Atributo-Valor , que es una respuesta clásica, aunque algo aterradora, a este tipo de problema. La creación de la interfaz de usuario para definir campos EAV suele ser mucho más compleja que para las columnas de la base de datos, y las consultas pueden ser bastante complicadas, pero para grandes cantidades de campos ( es decir , esquemas de matriz muy dispersa), puede ser la única forma de obtener El trabajo hecho.
fuente
Encontré una cruz algo similar recientemente.
Hice 2 mesas.
Él es todos tus objetos. U establece su nombre.
Y un tipo de este objeto: - para mí, los tipos disponibles eran inventario, inventario_artículo, oficina.
Y la configuración habitual era n elementos son secundarios o inventario, que también es secundario de la oficina y utilicé una tabla de unión para unir objetos entre sí
La tabla de configuración contiene cada nombre de campo para ese tipo de objeto específico y valor en valor.
Ejemplo de propiedades de oficina
Ubicación, teléfono, horario laboral
Y para artículos
Etc, todas estas propiedades son aplicadas por su modelo y guardadas en la tabla de configuración como filas separadas (sin embargo, use reemplazar no insertar para evitar varias filas para el mismo campo)
Entonces, cuando quiero una oficina, la cargo fácilmente con todas sus relaciones y configuraciones donde la configuración object_I'd (objetos solicitados)
Después de eso, giro todas las filas desde la configuración y eso es todo.
Y en caso de que quisiera que una configuración sea específica para un artículo en un inventario (no global) configuré object_I'd = lo haría de la tabla de relaciones object_objects y configuré settings.type = relationship_setting
Espero que entiendan lo que quiero decir. Intentaré reformatear la respuesta cuando llegue a una computadora portátil.
fuente
No, no es una mala práctica. Es bastante común. En términos OO, esto se llama herencia. Tiene un inventario de clase base Item y dos clases heredadas AudioCD y mobiliario.
Tiene que decidir cómo se almacenan en la base de datos del inventario de artículos, CD de audio y muebles.
Si la consulta fácil es lo más importante para usted y db-space / normalization no importa, implementaría el esquema de "tabla por jerarquía".
Si el espacio / normalización es lo más importante para usted y las consultas más complicadas no son un problema, implementaría el esquema "tabla por tipo".
Para obtener más detalles, consulte dotnet table-per-type-vs-table-per-Jerarquía-herencia o herencia de hibernación de Java .
fuente