La forma que le vamos a dar nosotros a la interfaz con nuestra persistencia es utilizando objetos "Repositorio". Tal vez los hayan escuchado nombrar como DAOs o Homes. Un repositorio es el lugar donde "viven" todos los objetos de un mismo tipo.
Un repositorio o home almacena objetos de diferente tipo, lo parametrizamos en la definición mediante el uso de generics. Entonces hablamos de la interfaz Repo<T> en Arena como un objeto que sabe donde viven los objetos del tipo T (pueden ser de clases diferentes pero comparten el mismo tipo T en común).
T debe ser subclase de Entity (definido en el package org.uqbar.commons.model), que le agrega
¿Qué servicios ofrece un repositorio?
El paquete org.uqbar.commons.model (de uqbar-domain) define las siguientes implementaciones:
Otras estrategias
El paquete arena-pers ofrece una implementación que persiste a un repositorio de grafos neo4j:
Los repositorios por lo general se definen como singletons, ya que
Para definir un repositorio podemos
Qué necesitamos redefinir para implementar un CollectionBasedRepo
Ejemplos: veamos el createExample y el getEntityType para un Repo de objetos clientes de una compañía de celulares
Y definimos un criterio de búsqueda by example para la búsqueda de clientes combina una búsqueda por número exacto, por nombre contiene y por modelo de celular exacto. Se busca que cumpla todos los criterios ingresados (AndPredicate).
Si no queremos trabajar la búsqueda "by example", debemos implementar nuestro propio método search. Ejemplo: implementamos una búsqueda ad-hoc de clientes por número o nombre:
El mismo ejemplo en Java puede verse en el ejemplo de los Celulares.
Si el repo es un Singleton, basta con referenciarlo mediante el mensaje RepoCelulares.instance. Otra técnica consiste en utilizar un objeto ApplicationContext.
Es importante generar un juego de datos de prueba: podríamos definir un método init() que se llame en el constructor del repo. El inconveniente que presenta este approach es que acopla un determinado repositorio al fixture o juego de datos de la aplicación, sin poder diferenciar distintos entornos (desarrollo, pruebas del TP, entrega final productiva, etc.). La alternativa recomendada entonces es diseñar un objeto que implemente la interfaz Bootstrap:
El método isPending() nos dice cuándo debe ejecutarse el método run():
En el método run() estará el script de inicialización del juego de datos.
Luego al instanciar la aplicación le pasamos un bootstrap:
La búsqueda se dispara mediante un searchByExample()
o bien con un search():
Una forma de actualizar / crear un objeto podría ser
El método getRepoCelulares() obtiene el repositorio de celulares (mediante el acceso al singleton global o bien utilizando la técnica del Application Context)