2009-02-17 20 views
19

Tengo un requisito para crear 'versiones' en una aplicación y me preguntaba cuál es la mejor manera de abordarlo.¿Qué patrón de diseño de versiones recomendaría?

que tienen este patrón general:

Modelo A tiene de muchos B

Cuando en la actualización de los atributos de una necesidad de ser versionados y (B) también necesitan ser versionado sus objetos asociados. Entonces la aplicación mostrará la versión actual de A, pero también debe ser posible ver las versiones anteriores de A y sus objetos asociados.

Me gustaría utilizar una tienda de documentos, sin embargo, esto es solo una parte de la aplicación y tener una tienda de documentos y una base de datos de relaciones introduciría más complejidad.

He considerado el uso de un esquema de estrella, pero antes de progresar me preguntaba si hay un patrón de diseño flotando para resolver este problema.

Esta pregunta se inclina hacia resolver el problema de almacenar las versiones de un objeto asociado en una base de datos relacional. Donde existe una necesidad inherente de poder consultar los datos de manera efectiva (es decir, la serialización del objeto no será suficiente).

Actualización: lo que estaba pensando/han implementado, pero quieren ver si el es "una mejor manera"

,---------. 1  * ,--------. 
| Model A |----------| Model B| 
`---------'   `--------' 
|PK  |   | a_id | 
|b_version|   |version | 
|version |   `--------' 
`---------' 

Donde quisiera estar duplicando el modelo A y todos los de B y asociado incrementando el atributo de versión. Luego, haga una selección para unirse a las B a través de b_version y b.version. Me pregunto si esto se puede hacer mejor.

Respuesta

7

No creo que no haya un patrón de diseño de GoF específico per se para el control de versiones porque existen muchas implementaciones de él.

La implementación más simple de control de versiones es una lista vinculada de objetos. Donde cada nodo en la lista es una nueva revisión de lo que sea que sea el objeto versionable. Para ahorrar espacio, también implementa un tipo de diff que muestra la diferencia entre las revisiones. De esta forma puede almacenar diffs en la base de datos, pero también la versión final del objeto versionable, ya que el sistema de control de versiones debería poder derivar las versiones intermedias.

El esquema de base principalmente podría ser algo como esto (se puede ver este patrón en la mayoría de los sistemas wiki):

+--------------------+ 1  * +-----------------------------+ 
| VersionableObject |---------| Diff      | 
+--------------------+   +-----------------------------+ 
| lastStateContent |   | difference     | 
| originalAuthor  |   | revision     | 
| #dates and whatnot |   | # userId, dates and whatnot |  
+--------------------+   +-----------------------------+ 

Si quieres ir hardcore con la ramificación y la materia que usted podría considerar echar un vistazo en DAG, que es lo que usan los sistemas modernos de control de versiones distribuidas.

Ahora, si hablamos de su ejemplo, hay una gran cantidad de objetos que deben guardarse en configuraciones. Es decir. tenemos que elegir las revisiones de los objetos que queremos para el modelo. Significa que tenemos una relación de muchos a muchos (que se soluciona con una mesa de intermediario), algo así como esto:

+---+ 1 * +---------------+ 1 * +-----------------+ * 1 +-------+ 
| B |-------| Diff   |-------| ModelSelection |-------| Model | 
+---+  +---------------+  +-----------------+  +-------+ 
      | revisionNo |  | {PK} configId | 
      | {FK} configId |  | {FK} modelId | 
      +---------------+  +-----------------+ 

espero que esto ayude.

+0

Esta implementación no resolverá el problema de mantener las relaciones entre las versiones y sus objetos asociados – MatthewFord

+1

deimos1986: por supuesto, lo hace, actualizado con un ejemplo de dbschema. puedes ver esto emergente en implementaciones wiki. Sugiero que busque en MediaWiki u otros sistemas wiki opensource y eche un vistazo a sus modelos de base de datos para obtener inspiración – Spoike

+0

Oh, quiere decir que tiene toda una configuración de objetos que necesita ser versionada ... – Spoike

1

Una combinación del Memento pattern con el Observer pattern se ajusta a sus necesidades. También eche un vistazo a Visitor pattern para una posible aplicación en su caso ...

+0

Parece que podría ayudar Supongo que mi pregunta se refiere al diseño en el nivel de la base de datos. ¿Cómo se puede continuar persiguiendo el Memento cuando tienen múltiples objetos asociados, que también deben persistir? – MatthewFord

+0

Cada objeto es responsable de almacenar su estado en la tabla correspondiente de la base de datos. Cuando cada objeto también tiene un atributo "versión", que se sincroniza a través del Observer en cada cambio, debe ser posible almacenar un estado consistente y reproducible. – Kosi2801

2

He resuelto este problema utilizando el plugin acts_as_versioned. Cuando lo aplica a un modelo, asume que hay un model_name_version además de la tabla model_name. Cada vez que se guarda un modelo, la versión anterior junto con una marca de tiempo se copia en la tabla model_name_version.

Este enfoque mantiene el tamaño de la tabla de modelos manejable mientras permite la búsqueda en versiones anteriores. No estoy seguro de que el complemento maneje el encadenamiento que desea de fábrica, pero no sería difícil agregarlo.

+0

He echado un vistazo a acts_as_versioned y otros plugins existentes, ninguno parece manejar este problema de asociaciones de versiones. la página wiki de AAV tiene esta pregunta abierta: ¿Alguien ha hecho algún trabajo para versionar las relaciones de claves foráneas? – MatthewFord

+0

Correcto, supongo que no. Sin embargo, los complementos son notablemente fáciles de modificar, y este cambio en particular no sería difícil. –

+0

He escrito un complemento para Sequel que implementa esto a lo largo de las líneas descritas en la pregunta. Me gustaría intentarlo de nuevo en AR y hacerlo de la mejor manera posible. Si echa un vistazo al código del complemento AAV, extenderlo para manejar n..n asociaciones no es trivial. – MatthewFord

8

Martin Fowler tiene algunos buenos artículos sobre los patrones de diseño de tiempo/a base de control de versiones - perfecto para ti:

http://martinfowler.com/eaaDev/timeNarrative.html

+0

Este enlace ha sido bueno para afirmar mis ideas, ya que está usando el tiempo como una dimensión donde propongo usar un número de versión. – MatthewFord

0

¿Qué pasa con el ahorro de una instantánea XML del shema base de datos desea versión más reciente? Y luego, ¿puedes cambiar el estado de la base de datos?

+0

para ser honesto mirando hacia atrás, como que esquivé el problema simplemente obteniendo toda la información que necesitaba y combinándola en un documento de gran json y volcándola en couchdb cuando necesitaba tomar una versión (de una colección de tablas). El problema no es tanto con el esquema, sino con la expansión de varias tablas. – MatthewFord