db4o - static1.1.sqspcdn.com

20
Db4o Muchas veces cuando se presenta un artículo tan técnico, se lo orienta hacia un público especializado o avanzado, y el enfoque es mostrar los últimos detalles del producto de turno, sin embargo si hicieramos esto aquí dejaríamos afuera a los lectores que descubren db4o. Tal vez no entenderían cuándo será viable su uso o bien qué es realmente lo grandioso de db4o. En cambio si el enfoque fuera “arranquemos desde cero”, los desarrolladores avanzados, o incluso intermedios, se aburrirían y dejarían de lado el artículo buscando las últimas novedades. Por ello les recomiendamos a quienes estén avanzados, que en el caso de no responder a sus dudas, consulten hacia el final de este artículo en donde se encuentran las direcciones URL de recursos, entre ellos los de la gran comunidad de usuarios de db4o, donde pueden realizar consultas específicas. Tanto si usted ha tenido alguna experiencia con bases de objetos (ODBMS), los conocidos como “mapeadores” objetos-relacionales (ORDBMS), es de la vieja guardia de las bases relacionales (RDBMS), como si jamás ha tenido experiencia persistiendo información y quiere averiguar si db4o es para usted, creemos que este artículo puede serle de ayuda. Qué no encontrará aquí La elección de un esquema de persistencia, aún cuando debería ser técnicamente una de las cuestiones menos polémicas debido a la enorme cantidad de documentación y comparativas realizadas y disponibles públicamente, ha sido desde hace unos años objeto de múltiples controversias. Sin embargo, el objetivo de este artículo no está centrado en los aspectos netamente comparativos, ni en convencer al lector de abandonar su preferencia por las bases relacionales o herramientas de mapeo, tareas que de por sí requerirían de un artículo aparte y cierta disposición especial al cambio. La idea aquí es presentar un vistazo a las características fundamentales de db4o, dejando a los lectores la posibilidad de generar nuevas entregas, ahondando en cuestiones que consideren de su interés. Introducción Vamos a ver entonces algunas características claves de db4o, la base de objetos nativa de alto rendimiento para .Net y Java. A continuación mostraremos cómo instalar y comenzar a utilizar este motor de persistencia. Y seguidamente incluiremos cómo resolver algunas tareas simples en C# (muy fácilmente adaptables a Java), una pequeña conclusión y daremos fuentes para más información. A grandes rasgos, las características fundamentales de db4o son: - Alto rendimiento: Ofreciendo notables ventajas con sistemas que utilizan objetos anidados o compuestos, o en donde existen referencias cruzadas, herencia o interacciones ricas entre los objetos.

Upload: others

Post on 22-Oct-2021

21 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Db4o - static1.1.sqspcdn.com

Db4o

Muchas veces cuando se presenta un artículo tan técnico, se lo orienta hacia un público especializado o avanzado, y el enfoque es mostrar los últimos detalles del producto de turno,   sin   embargo   si   hicieramos   esto   aquí   dejaríamos   afuera   a   los   lectores   que descubren  db4o.  Tal   vez  no   entenderían   cuándo   será   viable   su  uso  o  bien  qué   es realmente lo grandioso de db4o. En cambio si  el enfoque fuera “arranquemos desde cero”, los desarrolladores avanzados, o incluso intermedios, se aburrirían y dejarían de lado el artículo buscando las últimas novedades. Por ello les recomiendamos a quienes estén avanzados, que en el caso de no responder a sus dudas, consulten hacia el final de este artículo en donde se encuentran las direcciones URL de recursos, entre ellos los de la gran comunidad de usuarios de db4o, donde pueden realizar consultas específicas. 

Tanto   si   usted   ha   tenido   alguna   experiencia   con   bases   de   objetos   (ODBMS),   los conocidos como “mapeadores” objetos­relacionales (ORDBMS), es de la vieja guardia de las bases relacionales (RDBMS), como si jamás ha tenido experiencia persistiendo información y quiere averiguar si db4o es para usted, creemos que este artículo puede serle de ayuda.

Qué no encontrará aquí

La elección de un esquema de persistencia, aún cuando debería ser técnicamente una de las   cuestiones   menos   polémicas   debido   a   la   enorme   cantidad   de   documentación   y comparativas   realizadas  y  disponibles   públicamente,   ha   sido  desde  hace  unos   años objeto  de  múltiples  controversias.  Sin  embargo,  el  objetivo  de  este  artículo  no  está centrado   en   los   aspectos   netamente   comparativos,   ni   en   convencer   al   lector   de abandonar su preferencia por las bases relacionales o herramientas de mapeo, tareas que de por sí requerirían de un artículo aparte y cierta disposición especial al cambio. La idea aquí es presentar un vistazo a las características fundamentales de db4o, dejando a los  lectores  la posibilidad de generar  nuevas entregas,  ahondando en cuestiones que consideren de su interés.

Introducción

Vamos a ver entonces algunas características claves de db4o, la base de objetos nativa de alto   rendimiento   para   .Net   y   Java.   A   continuación   mostraremos   cómo   instalar   y comenzar   a   utilizar   este   motor   de   persistencia.   Y   seguidamente   incluiremos   cómo resolver algunas tareas simples en C# (muy fácilmente adaptables a Java), una pequeña conclusión y daremos fuentes para más información.

A grandes rasgos, las características fundamentales de db4o son:­ Alto   rendimiento:  Ofreciendo   notables   ventajas   con   sistemas   que   utilizan 

objetos   anidados   o   compuestos,   o   en   donde   existen   referencias   cruzadas, herencia o interacciones ricas entre los objetos.

Page 2: Db4o - static1.1.sqspcdn.com

­ Por   su  bajo   consumo   de   recursos,   (de   600Kb   a   800Kb   de   footprint)   es especialmente   apta   para   dispositivos   móviles   y   entornos   Clientes/Servidor, aunque no necesariamente limitada sólo a ellos.

­ Doble licencia: GPL (Open Source) y Comercial (que incluye soporte).­ Gran comunidad de usuarios. Alto nivel de respuesta y participación.­ Documentación:  Clara,  amplia  y  ordenada.  Orientada  a  ejemplos  y  de   fácil 

lectura.­ Dos modos de trabajo: Embebido y Cliente/Servidor.­ Transparencia Persistente / Consultas Nativas.­ Soporte de versionado.­ Portabilidad entre .Net, Mono y Java.­ Transacciones ACID: Atomicidad, Consistencia, Aislamiento, Durabilidad.­ Clientes de peso avalan su uso: BMW, Intel, Boeing, Ricoh, Seagate, Bosch, 

Novell, etc.

Instalación

Para   empezar   a   utilizar   db4o,   es   necesario   descargar   la   versión   apropiada   para   su equipo. Actualmente existen versiones para .NET 1.x y 2.0, para Java y para Mono. 

.NET

Lo primero que necesita saber es qué versión de .NET está instalada en su computadora. Una   comprobación   rápida   es   observar   si   existe   un   directorio   parecido   a "c:\WINDOWS\Microsoft.NET\Framework\", allí dentro debería tener un subdirectorio con el número de versión (ver tabla abajo) por cada versión instalada. La versión más profesional de esta verificación es ejecutar el siguiente script .VBS:

strComputer = "."

Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")Set colItems = objWMIService.ExecQuery("Select * from Win32_Product")

For Each objItem in colItems    If InStr(objItem.Name, "Microsoft .NET Framework") > 0 Then        Wscript.Echo objItem.Version    End IfNext

* Debería aparecer  un cuadro de diálogo por cada versión instalada.

Si no ha actualizado el framework .NET separadamente, la siguiente tabla puede darle una idea de la versión instalada en su equipo:

Visual Studio .NET  Nombre de Versión Número de versión2002 1.0 Beta 1 1.0.????.02002 1.0 Beta 2 1.0.2914.0

Page 3: Db4o - static1.1.sqspcdn.com

2002 1.0 RTM 1.0.3705.02002 1.0 SP1 1.0.3705.2092002 1.0 SP2 1.0.3705.2882002 1.0 SP3 1.0.3705.60182003 1.1 RTM 1.1.4322.5732003 1.1 SP1 1.1.4322.20322003* 1.1 SP1  1.1.4322.23002005 2.0  Beta 1 2.0.406072005 2.0 RTM 2.0.50727.42­ 3.0 RTM 3.0.4506.30

* = (Windows Server 2003 Version)

Si  tiene varias  versiones de  .NET instaladas,  es  posible  especificar con qué  versión desea utilizar db4o editando un archivo de configuración de la aplicación [1] (que no es más que un XML con extensión .config), sin embargo esto no es necesario ya que por omisión db4o tomará la última versión de .Net instalada. 

La distribución de Db4o para .NET consiste en un archivo instalador MSI, por lo que deberá tener habilitado el servicio "Windows Installer" para poder instalarlo. Ingrese en la   "Consola   de   administración  de  Microsoft"   escribiendo  services.msc  en   Inicio   ­> Ejecutar para poder habilitarlo si no está ya habilitado.

Java

Para empezar se debe tener instalada la máquina virtual Java de Sun (JRE). Por el uso de los  generics  y mejoras en la ejecución del  for,  se recomienda utilizar Java 5.0 en lo posible. Db4o también corre sobre la máquina virtual Java de Microsoft, para la cual se debe utilizar JDK 1.1 a partir de la versión 6.1 de Db4o.Db4o puede ejecutarse sobre las plataformas Java J2EE, J2SE y dialectos J2ME que soporten   reflexión   computacional   como   CDC,   PersonalProfile,   Symbian,   Savaje   y Zaurus. Está planeado el soporte sobre dialectos sin reflexión como CLDC, Palm OS y RIM/Blackberry. La distribución para Java viene en formato ZIP que debemos extraer en donde creamos conveniente.

Lenguajes

La siguiente tabla presenta los lenguajes y entornos soportados por Db4o:

Lenguaje/Entorno SoporteC# SíJava (JRE) SíJava (J#) SíVisualBasic.Net SíDelphi.NET SíC++ Administrado (C++/CLI)Ruby (JRuby) Vía reflector

Page 4: Db4o - static1.1.sqspcdn.com

Python (IronPython) SíPython (Jython) Vía reflectorBoo SíASP.NET SíCompact Framework Sí

Configuración

Suficiente hasta aquí con cuestiones de instalación. Db4o posee dos modos de trabajo: Embebido y Cliente/Servidor. A los propósitos de este artículo solo veremos el primer modo, dejando a futuras revisiones el modo cliente/servidor. Para poder distribuir aplicaciones con db4o, sólo necesita copiar una librería (.dll) muy pequeña y configurar algunas cosas en su entorno de desarrollo preferido (además de escribir el código necesario desde luego!).

VisualStudio .NET 2005

Estos son los pasos para comenzar a desarrollar con db4o 6.0 bajo este entorno:

1. Agregar la referencia de la dll en nuestro proyecto haciendo click con el botón derecho sobre References en el Solution Explorer. 

2. Elegir Add Reference y luego Browse3. Seleccionar db4o.dll, Open y finalmente Ok

Y   listo.   No   es   necesaria   la   administración   de   la   base   de   objetos.   Los   pasos   de configuración son similares para el entorno SharpDevelop

Eclipse

Sólo hay que agregar las referencias al .jar correspondiente al entorno de trabajo.

1. Abrir las propiedades del proyecto haciendo click con el botón derecho sobre el proyecto en el Package Explorer y seleccionando Properties.

2. Seleccionar Java Build Path y hacer click sobre la pestaña Libraries.3. Agregar el JAR correspondiente haciendo click en el botón Add External JARs y 

navegando hasta encontrar el JAR para la versión de Java que esté utilizando.

Page 5: Db4o - static1.1.sqspcdn.com

Ejemplo: Tienda de renta de DVDs

Vamos a trabajar con un ejemplo típico. Supongamos un cliente que hace un alquiler en nuestra tienda de renta de DVDs. A modo de ejemplo instanciemos una película y su respectiva copia física del DVD en nuestro sistema, y posteriormente un nuevo alquiler del cliente, asociando la información correspondiente. Gráficamente nuestras instancias quedarían así:

Por ahora, supongamos también que para el siguiente código de ejemplo tenemos un objeto “db” sobre el cual se pueden realizar dos operaciones, Set() y Commit(), que persisten  los  datos.  El  código que   generaría nuestras  instancias sería algo como lo siguiente: 

Page 6: Db4o - static1.1.sqspcdn.com

Java

(El proyecto que prueba este Script se llama ConsoleApplicatioDb4oTest­SimpleScript­JAVA)

C#

(El proyecto que prueba este Script se llama ConsoleApplicatioDb4oTest­SimpleScript­CS)

Si nunca trabajó con bases de objetos es importante que tenga en cuenta lo siguiente: En Db4o, las referencias a los objetos especifican la  relación  entre ellos, por lo tanto en nuestro ejemplo, la película (unaPelicula) y la copia física (copiaDVD) son almacenados implícitamente   al   hacer  db.Set(alquiler).   El  db.Commit()  finalmente   cierra   la transacción. Es fundamental que recuerde esta especie de principio que determina el funcionamiento de las bases de objetos.

Hasta  aquí   podemos   sacar  varias  conclusiones.  Como observamos,  con  db4o  no  es necesario crear un esquema de persistencia, es decir, no hay que hacer el diseño de la base de datos ya que es el modelo de clases de nuestro sistema lo que se persiste. Esto nos libera de varias cosas, entre ellas, el uso de herramientas de administración de base de datos, un administrador de base de datos, y de poseer conocimientos bases de datos relacionales (álgebra relacional, SQL), entre otras tareas.

Para los siguientes ejemplos, puede ser útil ir inspeccionando la base mientras se trabaja con ella.  Db4o posee  un  explorador  con  el  cual  podemos navegar  nuestras  bases  y realizar copias de seguridad, defragmentaciones, consultas, etc. Este se llama “Object Manager”, y se puede descargar desde el Centro de Descargas de Db4o (ver sección de 

// Creamos una nueva películaPelicula unaPelicula = new Pelicula("The Godfather", “Francis Ford Coppola”);

// Creamos un nueva copia física para la película// y asociamos la película a la copia físicaDvd copiaDVD = new Dvd(5, unaPelicula);

// Alquiler por 2 díasAlquiler alquiler = new Alquiler ("Juan Perez", copiaDVD, 2);

// Finalmente almacenamos el alquilerdb.set(alquiler);db.commit();

// Creamos una nueva películaPelicula unaPelicula = new Pelicula("The Godfather", “Francis Ford Coppola”);

// Creamos un nueva copia física para la película// y asociamos la película a la copia físicaDvd copiaDVD = new Dvd(5, unaPelicula);

// Alquiler por 2 díasAlquiler alquiler = new Alquiler ("Juan Perez", copiaDVD, 2);

// Finalmente almacenamos el alquilerdb.Set(alquiler);db.Commit();

Page 7: Db4o - static1.1.sqspcdn.com

enlaces). En la sección de herramientas de este artículo incluimos un listado de otras utilidades para db4o. Desde el Object Manager entonces, nuestro alquiler recientemente almacenado en la base, se vería de la siguiente manera:

Haciendo click en el ícono del árbol de cada ítem, se muestra una vista jerárquica del item seleccionado.

Para poder ejecutar el Object Manager, deberá tener instalada una máquina virtual Java en su sistema (por ejemplo el llamado Java Runtime Environment o JRE). La forma correcta de ejecución entonces es llamando al archivo por lotes (.bat) que se encuentra 

Page 8: Db4o - static1.1.sqspcdn.com

dentro de la carpeta del Object Manager y es el encargado de instanciar el applet de Java (.jar).

Entorno de trabajo

En el CD se encuentran dos proyectos para VisualStudio: uno que incluye acceso vía S.O.D.A. y otro  mediante Consultas Nativas, temas que trataremos a continuación. Ambos proyectos están  a la XP, es  decir, se incluyen tests Nunit para verificar su correcto funcionamiento.

En   principio   hagamos   algunas   consultas   muy   simples   sobre   Pelicula,   a   fin   de familiarizarnos   con   el   acceso   a   db4o,   y   luego   nos   moveremos   a   algunas   más interesantes. 

Trabajaremos con C# y Java que son los lenguajes más populares en la comunidad de db4o. En ambos casos, primero deberá incluir las rutas necesarias para que el enlazador encuentre los métodos:

Javaimport com.db4o.Db4o;import com.db4o.Query;

C#using Db4objects.Db4o;using Db4objects.Db4o.Query;

La API de db4o es similar en todos los lenguajes soportados. Usualmente la forma de trabajo es similar al siguiente molde:

Java// Crear una base si no existe, abrirla si ya existe.File file = new File("testDb4o.yap");String fullPath = file.getAbsolutePath();ObjectContainer db = Db4oFactory.openFile(file);try{

// realizar alguna acción con db4o// Ejemplos :

     db.set(obj); // Almacena un objeto en la base     db.commit();       // Realizar la transacción (y arrancar otra)     db.delete(obj);   // Eliminar un objeto en la base}finally{    db.close();         // Cerrar la base y liberar los recursos}

C#// Crear una base si no existe, abrirla si ya existe.IObjectContainer db = Db4oFactory.OpenFile("testDb4o.yap");try{

// realizar alguna acción con db4o

Page 9: Db4o - static1.1.sqspcdn.com

// Ejemplos :     db.Set(obj); // Almacena un objeto en la base     db.Commit();       // Realizar la transacción (y arrancar otra)     db.Delete(obj);   // Eliminar un objeto en la base}finally{    db.Close();         // Cerrar la base y liberar los recursos}

La base de objetos consta de un archivo denominado YAP, en donde se almacenarán los objetos serializados. A nivel de aplicación se lo llama ObjectContainer y es el objeto sobre el cual se realizarán las operaciones de persistencia (Set(), Get(), Commit(), etc.).

En los ejemplos a continuación, asumiremos que el código se ejecuta dentro del bloque try { … },  y están incluidos los espacios de nombres citados arriba a fin de que se encuentren las funciones necesarias.

Acceso a Db4o

Antes de ver  las formas de acceso a datos en Db4o, vamos a ponernos un poco en contexto: El acceso a los datos en una base de objetos es navigacional. La eficiencia en velocidad (una de las características notables de db4o) viene dada por el hecho de que las  referencias son almacenadas directamente en cada instancia,  mientras que en las bases   de   datos   tradicionales   (que   fueron   realizadas   antes   de  que   el   mecanismo  de herencia fuera ampliamente utilizado), el acceso es tabular, y lo que generalmente se intenta en estos casos para “salvar” la distancia con el mundo de objetos, es utilizar mapeadores Objeto­Relacionales, que incluyen API’s o lenguajes que dan la “ilusión” de trabajar con objetos.

En db4o existen tres formas de realizar consultas, cada una basada en una tecnología diferente. Estas son:

• S.O.D.A.: Simple Object Database Access / Acceso Simple a Bases de Datos de Objetos.

• Q.B.E.: Query By Example / Consulta por Ejemplo o Plantilla.

• N.Q.: Native Queries / Consultas Nativas

En un principio, db4o permitía acceder mediante Q.B.E. y S.O.D.A. [2], siendo esta última la interface preferida por ser una tecnología desarrollada por el mismo “creador” de db4o, Carl Rosenberg. La experiencia tomada con los usuarios durante el período 2003  –  2005  ha  valido  para   dar   cuenta  de   sus   limitaciones  y  proponer   una  nueva tecnología de acceso a datos persistidos, que supliera con estas limitaciones. A partir de la   versión  6   de   db4o,   las   Consultas   Nativas   (N.Q.)   se   convirtieron   en   la   interface principal   de   acceso,   mientras   que   S.O.D.A.   se   ha   mantenido   por   cuestiones   de compatibilidad y para el  uso de  consultas generadas  dinámicamente.  A pesar  de su reciente inclusión en db4o, las idea detrás de las Consultas Nativas no son un concepto nuevo; las colecciones de Smalltalk ya incluían esta capacidad desde su especificación en 1983. Veamos cuales son sus ventajas y desventajas principales:

Page 10: Db4o - static1.1.sqspcdn.com

Tecnología Ventajas Desventajas QBE  • Simplicidad, recomendada 

para principiantes.• Funcionalidades limitadas: Carece de 

consultas con juntores (AND, NOT, OR, etc).

• Se necesita agregar un constructor para crear objetos sin campos inicializados.

• No se puede consultar por valores nulos

SODA  • Independencia del lenguaje de programación utilizado.

• API simple. Minimiza el uso de cadenas para consultas

• Opera sobre propiedades• Introduce conceptos 

relacionados con grafos de nodos (natural a las bases de objetos): Descender y Restringir por nodos que pueden ser una o muchas clases, un atributo de una clase, o consultas mismas.

• No se verifican tipos en tiempo de compilación (query.Descend(“dirctor”) fallaría en tiempo de ejecución)

• Demasiado explícita (verbose).

• Opera sobre campos , (pelicula._director) en vez de propiedades (pelicula.getDirector() o pelicula.Director)

• Requiere actualizar las consultas cuando se refactoriza o modifica el modelo de clases.

• Consultas basadas en cadenas embebidas son blanco para ataques vía inyección de código.

NQs  • Interface recomendada para Db4o

• 100% segura en tipos: Verificación de errores semánticos y sintácticos en tiempo de compilación.

• 100% refactorizable• 100% nativas: no hay 

necesidad de aprender lenguajes de consultas o API’s

• Las consultas deben ser traducidas al lenguaje o API del motor, esto puede penalizar en rendimiento en el caso de consultas complejas, donde no es posible hacerlo sin instanciar algunos objetos persistidos.

Acceso mediante S.O.D.A. (Simple Object Database Access):

Al trabajar con db4o, debemos imaginar nuestros datos como en un grafo en el  que podemos navegar (o consultar), a diferencia de lo que haríamos con una base relacional donde los datos están tabulados y la idea predominante es combinar resultados en tablas.El acceso con S.O.D.A. se realiza mediante la clase Query, que es obtenida a través del ObjectContainer. Consideremos algunas operaciones típicas:

Java// Instanciamos un objeto query para realizar las consultasQuery query = db.query();

// Indicamos el objeto contra el cual se realizará la consultaquery.constrain(Pelicula.class);

Page 11: Db4o - static1.1.sqspcdn.com

////////////////////////////////////////////////////////////////// Configuramos la/s consulta/s en el objeto query////////////////////////////////////////////////////////////////

// Por dato particular : Recuperemos la(s) Pelicula(s) llamada(s) //                       “El Padrino” si existe(n).query.descend("nombre").constrain("El Padrino");

// Por negación : Recuperar las películas que no se llamen  //                “El Padrino” si existen.query.descend("nombre").constrain("El Padrino").not();

// Por conjunción : Recuperar las películas llamadas “El Padrino” y//                  cuyo director sea “Francis Ford Coppola”Constraint constr = query.descend("nombre").constrain("El Padrino");query.descend("director").constrain(“Francis Ford Coppola”).and(constr);

// Por disyunción : Recuperar las películas llamadas “El Padrino” o//                  cuyo director se llame “Francis Ford Coppola”Constraint constr = query.descend("nombre").constrain("El Padrino");query.descend("director").constrain(“Francis Ford Coppola”).or(constr);

// Por similitud: Recuperar las películas que contengan “God” en su títuloIConstraint constr = query.descend("nombre").constrain("God").like();

// Ordenando resultados de forma ascendentequery.descend("nombre").orderAscending();

// Ordenando resultados de forma descendentequery.descend("nombre").orderDescending();

// Ejecutar la consulta y Mostrar los resultadosObjectSet result = query.execute();listResult(result);

C#// Instanciamos un objeto query para realizar las consultasQuery query = db.Query();

// Indicamos el objeto contra el cual se realizará la consultaquery.Constrain(typeof(Pelicula));

////////////////////////////////////////////////////////////////// Configuramos la/s consulta/s en el objeto query////////////////////////////////////////////////////////////////

// Por dato particular : Recuperemos la(s) Pelicula(s) llamada(s) //                       “El Padrino” si existe(n).query.Descend("_nombre").Constrain("El Padrino");

// Por negación : Recuperar las películas que no se llamen  //                “El Padrino” si existen.query.Descend("_nombre").Constrain("El Padrino").Not();

// Por conjunción : Recuperar las películas llamadas “El Padrino” y//                  cuyo director sea “Francis Ford Coppola”Constraint constr = query.Descend("_nombre").Constrain("El Padrino");query.Descend("_director").Constrain(“Francis Ford Coppola”).And(constr);

// Por disyunción : Recuperar las películas llamadas “El Padrino” o

Page 12: Db4o - static1.1.sqspcdn.com

//                  cuyo director se llame “Francis Ford Coppola”Constraint constr = query.Descend("_nombre").Constrain("El Padrino");query.Descend("_director").Constrain(“Francis Ford Coppola”).Or(constr);

// Por similitud: Recuperar las películas que contengan “God” en su títuloIConstraint constr = query.Descend("_nombre").Constrain("God").Like();

// Ordenando resultados de forma ascendentequery.Descend("_nombre").OrderAscending();

// Ordenando resultados de forma descendentequery.Descend("_nombre").OrderDescending();

// Ejecutar la consulta y Mostrar los resultadosObjectSet result = query.Execute();listResult(result);

Observamos en los ejemplos previos que mediante una consulta se “desciende” por los nodos especificando un atributo.  Estos nodos pueden referir  a  tanto tipos primitivos como String en los ejemplos de _nombre o _director, o bien referir a otros objetos de nuestra aplicación, como veremos adelante en el ejemplo de acceso a objetos anidados. Finalmente, se “restringe” por el dato que queremos consultar ("El Padrino", “Stanley Kubrick”, Pelicula, DVD, etc). Observemos que las restricciones se dan en dos lugares: Al   comienzo,   cuando   especificamos   la   clase   de   lo   que   queremos   obtener (query.Constrain(typeof(Pelicula))) y al final mismo (Constrain(“Francis Ford Coppola”)).

A su vez, estas restricciones (Constraints), se pueden  combinar mediante juntores (Or, And,   Not)   y   operadores   de   comparación   (Equal,   Identity,   Like,   Contains,   Smaller, Greater, etc).

Por   lo   tanto,  descender  y  restringir  son   básicamente   las   ideas   principales   con S.O.D.A..   Descender   por   una   consulta   da   como   resultado   otra   consulta,   a   la   cual podemos descender nuevamente y realizar la restricción que nos interese: 

Java// Acceso a objetos anidadosquery.constrain(Alquiler.class);query.descend("copiaFisica").descend("pelicula").constrain(“nombre”);

C#// Acceso a objetos anidadosquery.Constrain(typeof(Alquiler));query.Descend("copiaFisica").Descend("pelicula").Constrain(“_nombre”);

Aquí   restringimos por Alquiler,  descendimos dos niveles por  copiaFisica y  pelicula, para luego restringir por nombre. Esta idea de descenso, conlleva de por sí la idea de profundidad. Veamos un caso en donde la profundidad es importante, la actualización de objetos. Pongamos por ejemplo que deseamos actualizar una Película:

Java

Page 13: Db4o - static1.1.sqspcdn.com

// Obtenemos una película utilizando un prototipo1. Query query = db.query();2. ObjectSet result = db.get(new Pelicula("El laberinto del Fauno"));3. Pelicula found = (Pelicula)result.next();// Actualizar el director4. found.director = “Guillermo del Toro”;5. db.set (found);// Mostrar resultados6. Result = db.get (new Pelicula("El laberinto del Fauno"));7. listResult(result);

C#// Obtenemos una película utilizando un prototipo1. Query query = db.Query();2. ObjectSet result = db.Get(new Pelicula("El laberinto del Fauno"));3. Pelicula found = (Pelicula)result.Next();// Actualizar el director4. found.Director = “Guillermo del Toro”;5. db.Set (found);// Mostrar resultados6. Result = db.Get (new Pelicula("El laberinto del Fauno"));7. listResult(result);

Observamos una forma alternativa de recuperar un objeto, especificando un prototipo, el equivalente de las líneas 2 y 3 sin prototipos sería:

C#1. Query query = db.Query();2. query.Constrain(typeof(Pelicula));3. query.Descend("_name").Constrain("El laberinto del Fauno");   ObjectSet result = query.Execute();

Java1. Query query = db.query();2. query.constrain(Pelicula.class);3. query.descend("name").constrain("El laberinto del Fauno");   ObjectSet result = query.execute();

Volviendo a la cuestión de la profundidad: Por omisión, sólo se actualizará  el objeto pasado como parámetro al método Set(), es decir, los miembros primitivos de ese objeto, por ello la profundidad de actualización (update depth) será  igual a 1. Es importante recordarlo   ya   que   en   general   un   modelo   de   objetos   medianamente   complejo seguramente utilizará más de un nivel de contención de objetos que no son primitivos. Si quisiéramos actualizar los objetos miembros, es decir, aquellos que están asociados a un objeto, debemos configurar el objeto raíz en cuestión para que actualice el grafo a la profundidad deseada.

Java// Actualizar el grafo completo de objetos desde PeliculaDb4o.configure().objectClass(Pelicula.class).cascadeOnUpdate(true);

C#

Page 14: Db4o - static1.1.sqspcdn.com

// Actualizar el grafo completo de objetos desde PeliculaDb4o.Configure().ObjectClass(typeof(Pelicula)).CascadeOnUpdate(true);

En general es conveniente realizar un plan de actualización de tal forma que al ejecutar las consultas, sólo se recuperen aquellos objetos que necesiten actualizarse y no más, a fin de no penalizar en velocidad de acceso.

Acceso mediante Consultas Nativas (NQs):

Como vimos, una base de objetos en db4o se crea mediante código escrito en el mismo lenguaje de desarrollo de la aplicación (C#, Java, Visual Basic, etc.), por lo que no es necesario   aprender   otros   lenguajes   como  SQL,   HQL  de   Hibernate,  OQL,   JDOQL, EJBQL, o SODA (además del lenguaje de desarrollo elegido) para persistir nuestros datos.  Esta  característica es   llamada  Transparencia Persistente,  "Native Queries"  o simplemente NQs, y está  marcando una tendencia entre los usuarios de Db4o.   Aún cuando considere que el uso o aprendizaje de otro lenguaje no es realmente relevante, existe otra gran dificultad con los lenguajes de consultas, y es que están basados en cadenas. Estas cadenas deben ser analizadas léxicamente y sintácticamente por el parser del  motor  de  persistencia,  esto  desde  ya  añade  tiempo y es  un proceso  propenso a errores. S.O.D.A incluso, que minimiza el uso de cadenas, también tiene la dificultad de que el compilador no puede verificar la validez del atributo de una clase.

Sin embargo, internamente, las Consultas Nativas funcionan sobre S.O.D.A., por lo que existe un conversor y un optimizador de consultas llamado “Native Query Optimizer” para maximizar su rendimiento.

En concreto, la idea tras NQs es posibilitar la forma más simple posible de realizar una consulta. Esta forma más simple trabajaría con una instancia prototípica, es decir, una creada   como   si   fuera   un   ejemplo,   pero   que   representa   a   todas   las   de   su   tipo. Naturalmente esto sería algo tan simple como:

Java// Obtener las películas que contienen la cadena “Padrino”Pelicula.getNombre().contains(“Padrino”);

C#// Obtener las películas que contienen la cadena “Padrino”Pelicula.Nombre.Contains(“Padrino”);

Siempre tenemos que tener en cuenta que lo principal de la consulta es esta expresión, que realiza la acción que nos interesa. A partir de aquí en adelante lo que veremos es de algún modo, cómo conformar a cada compilador y al motor de Db4o para que acepten esta expresión de la forma más simple posible. Esto no es fundamental, ni tampoco es complejo, pero sí es necesario aprenderlo para poder utilizar Consultas Nativas. 

Para que esto funcione entonces, lo primero que necesitaríamos es especificarle el tipo de   esta   instancia   prototípica   (película)   a   la   expresión   sobre   la   cual   realizamos   la consulta, y devolver los resultados en algún tipo de contenedor. Algo como:

Page 15: Db4o - static1.1.sqspcdn.com

Java// Obtener las películas que contienen la cadena “Padrino”(Pelicula pelicula) {  return pelicula.getNombre().contains(“Padrino”);}

C#// Obtener las películas que contienen la cadena “Padrino”(Pelicula pelicula) {  return pelicula.Nombre.Contains(“Padrino”);}

La próxima característica a agregar a la expresión necesita una introducción. Hace un instante   mencionamos   que,   internamente,   db4o   realiza   un   proceso   de   análisis, conversión   y   posible   optimización   sobre   las   consultas.   Esto   agrega   un   nuevo requerimiento a nuestra expresión, que debería ser de tal forma que pueda pasarse como parámetro al motor de la base de objetos, u otro procesador de consultas, y así poder ser modificada. 

Siempre priorizando la simplicidad sintáctica, necesitaríamos entonces un objeto que pueda referenciar una especie de método “anónimo” que sea usado como parámetro y sea modificable, ya sea bien optimizándose o simplemente traduciéndose a SODA. Esto es posible a partir de .NET 2.0 utilizando los llamados delegados. Un delegado es como un par objeto­método que funciona como una retrollamada (callback), y sirve para tratar a un método como un objeto de primera clase, y así pasarse como parámetro a otros métodos.   Los   delegados   son   muy   usados   en   el   mundo   de   .NET   para   realizar notificaciones de eventos, ejecuciones encadenadas y algunos otros casos en los que se necesite reflexión computacional. 

En Java 1.2 – 1.4 y 5.0,  es  posible  emular  este  comportamiento utilizando  la  clase Predicate  como una clase anónima, y escribiendo en un método  match  la expresión dentro de ella, un detalle que le resta simplicidad en comparación con la versión de C#. En el caso particular de Java 5.0, se puede hacer uso de los  generics. En código esto sería:

Java// Obtener las películas que contienen la cadena “Padrino”new Predicate() {  public boolean match(Pelicula pelicula) {    return pelicula.getNombre().contains(“Padrino”);}

C#// Obtener las películas que contienen la cadena “Padrino”delegate (Pelicula pelicula) {  return pelicula.Nombre.Contains(“Padrino”);}

Lamentablemente la sintaxis para definir métodos anónimos en C# y Java aún es algo excesiva (esto tal vez cambie en el futuro con versiones posteriores de los lenguajes), en comparación con sus definiciones “equivalentes” en otros lenguajes, por ejemplo las expresiones lambda en Haskell o los CompiledMethods o bloques de Smalltalk. Aún así 

Page 16: Db4o - static1.1.sqspcdn.com

pese a esta desventaja, en nuestra opinión, su uso es recomendable considerando sus contrapartes   en   lenguajes   como SQL o   lenguajes  de  consultas  basadas  en  cadenas, propensos   a   errores   de   tipeo,   dificultades   para   depuración,   y   a   utilizar   cientos   de palabras claves. Existen también algunas ventajas adicionales como la posibilidad de realizar consultas dinámicas y parametrizadas,   temas que podrían tratarse en futuros artículos.Volviendo a nuestra expresión, finalmente agregamos el contenedor para los resultados, quedando:

Java 5.0List <Pelicula> peliculas = database.query <Pelicula> (  new Predicate <Pelicula> () {    public boolean match(Pelicula pelicula) {      return pelicula.getNombre().contains(“El Padrino”);

}});

Java 1.2 – 1.4List peliculas = database.query (  new Predicate () {    public boolean match(Pelicula pelicula) {

  return pelicula.getNombre().contains(“El Padrino”);}

});

C# .NET 2.0IList <Pelicula> peliculas = db.Query <Pelicula> (

delegate (Pelicula pelicula) {  return pelicula.Nombre.Contains(“El Padrino”);});

C# .NET 1.1IList <Pelicula> peliculas = db.Query (new PeliculaQuery());Public class PeliculaQuery : Predicate{

Public boolean match(Pelicula pelicula) {  return pelicula.Nombre.Contains(“El Padrino”);}

};

Vamos ahora a reescribir nuestras consultas S.O.D.A, a la Consultas Nativas:

Java

// Consulta por dato particular : Recuperar la(s) Pelicula(s) // llamada(s) “El Padrino” si existe(n).

List <Pelicula> peliculas = this.db.query(new Predicate<Pelicula>() {   public boolean match (Pelicula pelicula) {       return pelicula.get_nombre().equals(“El Padrino”);   }});

// Por negación : Recuperar las películas que no se llamen  //                “El Padrino” si existen.

Page 17: Db4o - static1.1.sqspcdn.com

List <Pelicula> peliculas = this.db.query(new Predicate<Pelicula> (){   public boolean match (Pelicula pelicula) {    return !pelicula.get_nombre().equals(“El Padrino”);   }});

// Por conjunción : Recuperar las películas llamadas “El Padrino” y//                  cuyo director sea “Francis Ford Coppola”List <Pelicula> peliculas = this.db.query(new Predicate <Pelicula> (){   public boolean match (Pelicula pelicula) {      return pelicula.get_nombre().equals(“El Padrino”) &&   

pelicula.get_director().equals(“Francis Ford Coppola”);   }});

// Por disyunción : Recuperar las películas llamadas “El Padrino” o//                  cuyo director se llame “Stanley Kubrick”List <Pelicula> peliculas = this.db.query(new Predicate <Pelicula>(){   public boolean match (Pelicula pelicula) {      return pelicula.get_nombre().equals(“El Padrino”) || 

pelicula.get_director().equals(“Stanley Kubrick”);     }});

// Por similitud: Recuperar las películas que contengan “God” en su títuloList <Pelicula> peliculas = this.db.query(new Predicate <Pelicula>(){   public boolean match (Pelicula pelicula) {

return pelicula.get_nombre().contains("God");}});

// Ordenación: Alfabéticamente por nombre especificando un criterio // de comparación con un delegado anónimoComparator<Pelicula> peliculaCmp = new Comparator<Pelicula>() {   public int compare (Pelicula pel1, Pelicula pel2){    return pel1.get_nombre().compareTo(pel2.get_nombre());   }};    List <Pelicula> peliculas = this.db.query(new Predicate<Pelicula>() {   public boolean match (Pelicula pelicula) {

return true;   }}, peliculaCmp);

C#

// Consulta por dato particular : Recuperar la(s) Pelicula(s) // llamada(s) “El Padrino” si existe(n).

IList<Pelicula> peliculas = db.Query<Pelicula>(delegate(Pelicula peliculaDb) {  return peliculaDb.Nombre(“El Padrino” );});

// Por negación : Recuperar las películas que no se llamen  //                “El Padrino” si existen.IList<Pelicula> peliculas = db.Query<Pelicula>(delegate(Pelicula peliculaDb) {  return ¡peliculaDb.Nombre(“El Padrino” );

Page 18: Db4o - static1.1.sqspcdn.com

});

// Por conjunción : Recuperar las películas llamadas “El Padrino” y//                  cuyo director sea “Francis Ford Coppola”IList<Pelicula> peliculas = db.Query<Pelicula>(delegate(Pelicula peliculaDb) {  return (peliculaDb.Nombre == “El Padrino”) &            (peliculaDb.Director == “Francis Ford Coppola”); });

// Por disyunción : Recuperar las películas llamadas “El Padrino” o//                  cuyo director se llame “Stanley Kubrick”IList<Pelicula> peliculas = db.Query<Pelicula>(delegate(Pelicula peliculaDb) {  return (peliculaDb.Nombre == “El Padrino”) |            (peliculaDb.Director == “Stanley Kubrick”); });

// Por similitud: Recuperar las películas que contengan “God” en su título

IList<Pelicula> peliculas = db.Query<Pelicula>(delegate(Pelicula peliculaDb) {  return (peliculaDb.Nombre.Contains == “God”); });

// Ordenación: Alfabéticamente por nombre especificando un criterio de // comparación con un delegado anónimoComparison<Pelicula> peliculaCmp = new Comparison<Pelicula>(delegate(Pelicula p1, Pelicula p2){  return p2.Nombre.CompareTo(p1.Nombre);});

IList<Pelicula> peliculas = db.Query<Pelicula>   (delegate(Pelicula peliculaDb) { return true; }, peliculaCmp);

Debido a las ventajas mencionadas anteriormente, existe dentro de la comunidad Db4o una marcada tendencia hacia las Consultas Nativas a pesar de su reciente novedad en el mundo de  desarrolladores   Java  y   .Net.  Una   forma  conveniente  de  acostumbrarse  al trabajo con Consultas Nativas es primero escribir   la expresión de la consulta,   luego agregar   la  colección devuelta,  y   finalmente encabezado correspondiente  al  delegado para C# o el predicado en el caso de Java, que suelen tener una forma más similar entre todas ellas. 

Muchos desarrolladores configuran y utilizan unos archivos en formato XML llamados snippets  en  VisualStudio  o  templates  en  Eclipse,   que   insertan   el   texto   reusable   en nuevos contextos o aplicaciones (boilerplates) y pueden ser de especial utilidad en estos casos.

Herramientas

Existen   algunas   herramientas   y   conectores   (plugins)   adicionales   interesantes, descargables desde el Centro de Descargas de Db4o:

Page 19: Db4o - static1.1.sqspcdn.com

ObjectManager GUI Administration Tool: Es una interface gráfica realizada en Java para manipular bases Db4o.

db4o  Replication  System  (dRS):  Es  una  herramienta  de  compatibilidad  basada  en Hibernate (un framework de persistencia y de mapeo objeto­relacional muy popular) que permite replicar datos desde db4o hacia db4o o algún RDBMS, o bien desde un RDBMS hacia db4o.

Db4o.Binding.NET:   Incluye  clases  para   trabajo con  listas  en memoria  y  enlace  de resultados   de   consultas   con   controles   de   Windows   Forms   y   Windows   Presentation Forms (parcialmente). Soporta consultas, filtros, ordenación, paginación, etc. 

Db4o Eclipse: Plugin documentado para Eclipse con acciones para realizar copias de resguardo, defragmentación, etc.

Conclusión

Tal   vez   le   haya   sorprendido   lo   poco  que  hay  que   aprender   con  db4o.  En   la   jerga académica esto se llama “gap semántico”, lo que significa en pocas palabras, es que el uso de  la   tecnología  de objetos  (T.O.)  está   “más cerca“ del   lenguaje natural  de   los humanos,  por el  simple hecho de que requiere que usted conozca menos cuestiones relacionadas con la máquina en sí. Esto permite a los desarrolladores concentrarse más en el problema a resolver, el llamado dominio del sistema, en vez de invertir tiempo en cuestiones propias de la tecnología elegida. 

Enlaces

Sitiohttp://www.db4o.com/espanol  (con documentación en castellano)Forohttp://developer.db4o.com/forums/15/ShowForum.aspx  (para interactuar con la comunidad)Wikihttp://developer.db4o.com/ProjectSpaces/view.aspx/Espanol (un espacio web gratuito de trabajo comunitario en castellano)Bloghttp://developer.db4o.com/blogs/espanol/default.aspx (para anuncios y noticias)Centro de Descargas:http://developer.db4o.com/filesDescargas de la Comunidad Hispanahttp://developer.db4o.com/files/folders/spanish/default.aspx

Referencias

Page 20: Db4o - static1.1.sqspcdn.com

[1] Cómo: Utilizar el  archivo de configuración de una aplicación para determinar la versión   de   .NET   Framework   que   se   va   a   usar :  http://msdn2.microsoft.com/es­es/library/9w519wzk(VS.80).aspx[3] Sitio de S.O.D.A.  http://sodaquery.sourceforge.net[2] David Taylor. Object Technology. Editorial Addison Wesley (2da Ed. 1997) capítulo 6.[3] William R. Cook, Carl Rosenberg. Native Queries for Persistent Objects. A Design White Paper. National Science Fundation (15 de febrero de 2006).[4] Adele Goldberg, D. Robson. Smalltalk­80: the Language and Its Implementation. Editorial Addison Wesley (1983).[5] JRE Test (verificar si está instalada y funcional la máquina virtual de Java de Sun) http://java.com/en/download/help/testvm.xml[6] Máquina Virtual de Java de Sun : http://developers.sun.com/downloads/top.jsp[7] Jim Paterson, Stefan Edlich, Henrik Horning, Reidar Horning. The definitive guide to Db4o. Apress (2006).