2010-03-10 77 views
8

Una cosa que continuamente he encontrado muy confusa sobre el uso de una base de datos de objetos como db4o es cómo se supone que debe manejar migraciones complejas que normalmente serían manejadas por SQL/PL-SQL.Manejo de mantenimiento de datos en bases de datos de objetos como db4o

Por ejemplo, imagina que tienes una tabla en una base de datos relacional llamada my_users. Originalmente tenía una columna llamada "full_name", ahora que su software está en V2, desea eliminar esta columna, dividir los nombres completos en un espacio en blanco y poner la primera parte en una columna llamada "first_name" y la segunda en una columna llamado last_name. En SQL simplemente rellenaría las columnas "first_name" y "second_name" y luego eliminaría la columna original llamada "full_name".

¿Cómo puedo hacer esto en algo como db4o? ¿Escribo un programa Java que los guiones busquen todos los objetos de User.class, estableciendo full_name en null mientras configuran first_name y last_name? Cuando hago mi próxima confirmación svn, no habrá field/bean-property correspondiente a full_name, ¿esto sería un problema? Parece que para usarlo en una aplicación de producción donde cambie mi "esquema" me gustaría escribir un script para migrar datos de la versión x a la versión x + 1 y luego en la versión x + 2 realmente eliminar las propiedades que estoy tratando de Deshágase de la versión x + 1 ya que no puedo escribir una secuencia de comandos Java para modificar las propiedades que ya no forman parte de mi tipo.

Parece que parte del problema es que un RDBMS resuelve a qué objeto se refiere basado en un simple nombre de cadena basado en mayúsculas y minúsculas, en un lenguaje como el de Java es más complicado que esto, no puede hacer referencia a propiedad si el getter/setter/field no es un miembro de la clase cargada en el tiempo de ejecución por lo que esencialmente necesita tener 2 versiones de su código en el mismo script (hmm, los cargadores de clases personalizados suenan como un dolor), tenga la nueva versión de su la clase almacenada pertenece a otro paquete (suena desordenado), o usa la estrategia de la versión x + 1 x + 2 que mencioné (requiere mucha más planificación). Quizás haya alguna solución obvia que nunca obtuve de los documentos db4o.

¿Alguna idea? Espero que esto tenga algo de sentido.

Respuesta

10

En primer lugar, db4o se encarga de la 'simple' scenarios like adding or removing a field automatically. Cuando agrega el campo, todos los objetos existentes tienen el valor predeterminado almacenado. Cuando elimina un campo, los datos del objeto existente aún están en la base de datos y aún puede acceder a él. Renombrar campos, etc. son special 'refactoring'-calls.

Ahora su escenario que haría algo como esto:

  1. Retire el campo 'FULL_NAME', añadir los nuevos campos 'nombre' y 'second_name'
  2. iterar sobre todo 'Address'-objetos
  3. acceso al campo de edad a través de la 'StoredClass'-API
  4. Split, cambiar, actualizar el valor etc. Establezca los nuevos valores en el nuevo campo y almacene el objeto.

Supongamos que tenemos una clase 'Dirección'. El campo 'full_name' ha sido eliminado. Ahora queremos copiarlo al 'primer nombre' y 'apellido'. Entonces podría ir como esto (Java):

ObjectSet<Address> addresses = db.query(Address.class); 
    StoredField metaInfoOfField = db.ext().storedClass(Address.class).storedField("full_name", String.class); 
    for (Address address : addresses) { 
     String fullName = (String)metaInfoOfField.get(address); 
     String[] splitName = fullName.split(" "); 
     address.setFirstname(splitName[0]); 
     address.setSurname(splitName[1]); 
     db.store(address); 
    } 

como usted sugiere, se escribiría la migración de código para cada versión de golpe. Ya no se trata de un campo de tu clase, tienes que acceder a él con la API 'StoredField' como la anterior.

Usted puede obtener una lista de todas las clases '' almacenados con ObjectContainer.ext().storedClasses(). Con StoredClass.getStoredFields() puede obtener una lista de todos los campos de la tienda, no importa si el campo ya no existe en su clase. Si una clase ya no existe, aún puede obtener los objetos y acceder a ellos a través de la clase 'GenericObject'.

Actualización: Para los escenarios complexer en una base de datos necesita para migrar a través de múltiples-versión-pasos.

Por ejemplo, en la versión v3 la dirección a objetos es completamente diferente. Por lo tanto, el 'migration-script' para v1 a v2 ya no tiene los campos necesarios (firstname y surename en mi ejemplo). Creo que hay múltiples posibilidades para manejar esto.

  1. (Suponiendo Java para esta idea. Ciertamente hay un equivalente en .NET). Puede hacer que el paso de migración sea Groovy-script. Entonces, cada uno de los guiones no interfiere con el otro. Luego, define 'clases' las clases necesarias para la migración allí. Entonces, cada migración tiene sus propias clases de migración. Con aliases vincularías tus clases groovy-migration a las clases reales de Java.
  2. Creación de clases de refactorización para escenarios complejos. También vincula estas clases con aliases.
2

Me estoy tomando un tiro salvaje aquí, porque no refactorizar demasiados datos en mi vida.

Estás haciendo una comparación extraña: si querías 'migrar en caliente' la base de datos, probablemente tendrías que hacer el método de control de versiones x+1, x+2 que describiste, pero realmente no lo sé - No lo haría Tampoco sé cómo hacer esto con SQL ya que no soy un experto en DB.

Sin embargo, si está migrando "frío", puede hacerlo en un solo paso creando un nuevo objeto de los datos anteriores, almacenar el nuevo objeto, eliminar el objeto antiguo para cada objeto en la tienda. Ver db4o reference.

Pero, sinceramente, el mismo proceso en un RDBMS también es complicado, porque deberá desactivar las comprobaciones de restricciones (y posiblemente desencadenantes, etc.) para realizar la operación, tal vez no en el ejemplo que proporcionó. pero para la mayoría de los casos del mundo real. Después de todo, la división de cuerdas es tan fácil que habrá poca ganancia.

En SQL yo simplemente llenar "nombre apellido" y "columnas" second_name

Sí, con una operación de cadena sencilla dividida , puede simplemente hacer eso. Pero en un escenario de refactorización típico, estás reestructurando objetos basados ​​en conjuntos de reglas grandes y complicados que pueden no ser fácilmente expresados ​​en SQL, pueden necesitar cálculos complejos o fuentes de datos externas.

Para hacer eso, también debe escribir el código.

Después de todo, no veo mucha diferencia en los dos procesos. Siempre tendrá que tener cuidado con los datos en vivo, y ciertamente hará una copia de seguridad en ambos casos. Refactorizar es divertido, pero la persistencia es difícil, por lo que sincronizarlo es un desafío en cualquier caso.

Cuestiones relacionadas