2009-08-16 15 views
5

Pronto comenzaré a trabajar en un proyecto que (a partir de la especificación) me recuerda un poco a StackOverflow. Básicamente, es una aplicación web que tiene contenido controlado por el usuario.Implementando la versión Control de objetos DB

Una de las características que me hace dar vueltas en mi mente es el control de versiones. Aquí en StackOverflow, cada pregunta y respuesta puede tener múltiples revisiones. Esto es bastante simple de implementar cuando solo tiene un tipo de objeto (y, en este caso, su texto).

Por lo tanto, para mis páginas simples, estoy configurado.

El problema aparece cuando considero que algunos objetos que deben estar bajo control de versiones tienen relaciones. Para proporcionar un ejemplo concreto, permítanme elegir un dominio aleatorio análogo:

Digamos que estaba implementando un sitio similar a Wiki para hacer un seguimiento de la información del libro/autor. El objetivo principal del sitio sería crear y actualizar páginas de "Autor", que, como texto, es bastante simple (como se indicó anteriormente). Sin embargo, agreguemos una asociación uno a muchos entre autores y libros (en otras palabras, los libros serían objetos separados, ya que obviamente una persona podría autorizar muchos libros). Cada libro tendría un enlace desde la página del autor a una página informativa sobre ese libro.

Para el usuario, hay poca diferencia entre el "Resumen" basado en texto que describe el autor y los vínculos entre ese autor & sus obras. Por lo tanto, tenemos un requisito para implementar la función de "revisión"/edición para páginas de autor, páginas de libros, y, la asociación entre autores y libros. En otras palabras, el usuario debería poder editar, ver el historial de y deshacer páginas de autor, páginas de libros y asociaciones entre los dos.

Esto se vuelve aún más complicado cuando esa relación se convierte en una relación de muchos a muchos, donde se pueden enumerar varios autores que contribuyeron a un libro.

Tengo una serie de soluciones en mente, pero ninguna de ellas es tan limpia como me gustaría (e involucran al menos algunos códigos repetidos/almacenamiento de datos redundantes), y, aunque veo algo común en todo el lugar aquí, siento que realmente no he podido extraerlo mejor, especialmente a nivel de base de datos. No quiero sesgar las respuestas dadas, así que no voy a darlas de inmediato.

Entonces, ¿cómo diseñaría este sistema a nivel de base de datos? Estoy buscando las especificaciones de la tabla aquí, y posiblemente una descripción de cómo las usaría, si no es inmediatamente obvio. Para aquellas respuestas que puedan ser relevantes, voy a usar ASP.NET y Linq-to-SQL (me siento cómodo con many-to-many en LTS) o Entity Framework.

EDIT: Para aclarar, entiendo el diseño básico de DB, normalización, tablas de asignación de muchos a muchos, etc. Estoy buscando una solución limpia para esta situación específica.

EDIT 2: Estoy buscando una solución generalizable, ya que puede haber más subobjetos en el sistema que solo libros. El autor puede estar relacionado con otros autores, revistas, eventos, etc., etc. Siento que estoy repitiendo mucho trabajo si implemento el historial individualmente para cada uno.

+0

@JoshJordan: No te disculpes. Arregla la pregunta para ser más al grano. –

Respuesta

5

Esto es un problema bastante común en el almacenamiento de datos. Usan "dimensiones que cambian lentamente".

Tiene que haber algunas reglas, sin embargo, si va a intentar tener datos "versionados".

  1. Debe registrar la relación autor-libro como inicialmente se define. Esta es la relación oficial de Autor-Libro. Es algo que la gente del almacén de datos llama una "tabla de hechos sin hechos". Son pares de llaves.

  2. Los libros son una dimensión del hecho del autor del libro. El libro puede cambiar Existen numerosos algoritmos de dimensiones que cambian lentamente. Puede mantener solo la última tabla de historial separada de la actual. Mantenga el historial y la actualidad en una tabla con una bandera para distinguir el actual del historial.

  3. Los autores son una dimensión del hecho del autor del libro. El autor puede cambiar De nuevo, hay numerosos algoritmos de SCD. Lea sobre las elecciones. Por The Data Warehouse Toolkit de Ralph Kimball para más información.

Tenga en cuenta que la relación (autor a libro) es un hecho y no necesita versiones. Es un hecho. No "cambia". Es verdadero o fue puesto en la base de datos por error, en cuyo caso, debe ser eliminado. Los hechos no necesitan números de versión.

En un esquema de estrella más sofisticado, sus hechos tienen medidas. Precio, volumen vendido, costo, beneficio, etc. Estos también se registran en la tabla de hechos. Estas piezas de información pueden variar con el tiempo. Por lo tanto, casi siempre tiene una dimensión de tiempo para cada hecho.

Por lo tanto, el tiempo es una dimensión del hecho del autor del libro. Si este hecho puede cambiar, el período de tiempo aplicable se registra como parte del hecho.

La dimensión de tiempo no es exactamente lo mismo que un número de versión. Es un poco mas simple Afirma que en un punto dado en el tiempo, el hecho era cierto. Si el hecho cambia, agrega un hecho nuevo con una marca de tiempo diferente.

Puede, dado un punto particular en el tiempo, localizar los hechos relevantes y los valores de dimensión asociados.

+0

Buen espectáculo. Gracias. La literatura de SCD es útil. – JoshJordan

+0

Gracias. Debería reconsiderar por qué/si quiero tener una tabla de historial separada para cada tabla, en lugar de mantener los datos antiguos de cada tabla en la tabla misma. – ChrisW

+0

@ChrisW: El diseño de SCD es difícil. Depende del tipo de consultas que obtendrá. ¿Las personas hacen consultas "contrafácticas" ("¿y si ...")? "¿Qué pasa si estas cifras de ventas fueron informadas por la definición de región del año pasado?" En este caso, es posible que se una a filas de dimensiones históricas. Si haces esto rara vez, una tabla de historia separada no duele. Si lo hace con frecuencia, una tabla de historial separada puede ser demasiado compleja. –

1

Tengo una tabla para cada tabla: es decir, Autor y Libro.

Existe la relación de clave foránea habitual (lo que sea que sea) entre las tablas.

Cada tabla también tiene una tabla de historial, es decir, AuthorHistory y BookHistory. Estas tablas de historial contienen las versiones antiguas/obsoletas de los registros (por ejemplo, cada registro de Autor eliminado y/o editado). No hay una relación de clave externa a/de las tablas de historial.


Editar:

Parte de la funcionalidad es similar para cada tabla: por ejemplo, no importa qué tabla, la actualización de un registro significa almacenar la copia antigua de la historia de registro en la tabla correspondiente del te. Implemento esta funcionalidad usando desencadenadores de base de datos (activadores de actualización y eliminación para cada tabla); porque el motor de base de datos que estoy utilizando admite desencadenantes, y eso lo hace transparente para la aplicación. El código dentro de estos desencadenadores es similar de una tabla a la siguiente (solo los nombres de la tabla y la lista de nombres de campo difieren de una tabla a la siguiente).


¿Qué pasa con la situación de muchos a muchos? Esto es más difícil porque en realidad se podría no tener antecedentes cartografía de un autor para un libro, pero ha tenido previamente una y la necesidad de demostrar que como un elemento del historial

Edición # 2:

yo no tengo implementado historia de una relación muchos-a-muchos situación todavía, pero no veo por qué no sería el mismo, es decir:

  • los muchos-a-muchos relación es implementado por la existencia de una mesa de BookAuthor , cada uno de cuyos registros es solo BookId plus AuthorId.
  • Las relaciones históricas se encuentran en una tabla BookAuthorHistory correspondiente.
+0

¿Qué pasa con la situación de muchos a muchos? Esto es más difícil porque, en realidad, no puede haber un mapeo de registros de un autor en un libro, pero anteriormente lo tenía y debe mostrarlo como un elemento del historial. – JoshJordan

+0

De hecho, tienes razón. Desafortunadamente, esta no es una solución muy general/escalable. Requiere una nueva tabla de historial para cada nueva tabla implementada. – JoshJordan

+0

No veo que no sea general/escalable al respecto: IMO es una solución "general" en el sentido de que es una solución que funciona para cualquier conjunto de tablas. – ChrisW

1

Suena casi como un caso de uso ideal para CouchDB. Con esta base de datos orientada a documentos obtiene revisiones gratuitas (cada documento se revisa automáticamente a menos que configure su base de datos diferente).

También es posible tener relaciones m: n entre documentos. Sin embargo, migrar a CouchDB es un gran paso y no sé qué tan accesible es desde ASP.NET. Pero leer algunos tutoriales introductorios no puede doler.

Cuestiones relacionadas