3. API de consulta


Ya hemos visto como recuperar objetos desde db4o vía QBE. Mientras esta alternativa es fácil e intuitiva, hay situaciones en donde que no es suficiente.

-Hay consultas que simplemente no pueden ser expresadas con QBE: Recuperar todos los pilotos con mas de 100 puntos, por ejemplo.
-Crear un objeto prototipo puede traer efectos secundarios indeseados.
-Los valores por defecto (Ej. null) pueden no ser aceptados por el constructor de clase del dominio.
-Se puede querer hacer una consulta por un valor por defecto.

db4o provee una API dedicada de consulta que puede ser usada en esos casos.

Necesitamos nuevamente algunos pilotos en nuestra base de datos para explorarla.


[storeFirstPilot]
Pilot pilot1=new Pilot("Michael Schumacher",100);
db.set(pilot1);
System.out.println("Stored "+pilot1);



[storeSecondPilot]
Pilot pilot2=new Pilot("Rubens Barrichello",99);
db.set(pilot2);
System.out.println("Stored "+pilot2);



    3.1. Consultas simples


    Primero, veamos como nuestras consultas QBE ya conocidas son expresadas dentro de la API de consultas. Realizamos esto recuperando un objeto Query 'limpio' del ObjectContainer y agregándole instancias de Constraint. Para encontrar todas las instancias de Piloto, restringimos la consulta con el objeto clase Piloto.


    [retrieveAllPilots]
    Query query=db.query();
    query.constrain(Pilot.class);
    ObjectSet result=query.execute();
    listResult(result);


    Básicamente, estamos intercambiando nuestro prototipo "real" por una meta descripción de los objetos que quisiéramos encontrar: un grafo de consulta hecho a partir de los nodos de consulta y los requerimientos. Un nodo de consulta es un receptáculo para un objeto candidato, un requerimiento decide si agregar o excluir candidatos del resultado.

    Nuestro primer y simple grafo queda así.



    Estamos pidiendo que cualquier objeto candidato (aquí: cualquier objeto en la base de datos) que sea de tipo Piloto sea agregado a nuestro resultado.

    Para recuperar un piloto por nombre, tenemos que restringir un poco mas los pilotos candidatos descendiendo a su campo nombre y restringir este con la respectiva cadena candidata.


    [retrievePilotByName]
    Query query=db.query();
    query.constrain(Pilot.class);
    query.descend("name").constrain("Michael Schumacher");
    ObjectSet result=query.execute();
    listResult(result);


    ¿ Qué significa aquí 'descender' ? Bueno, así como hicimos con nuestros prototipos 'reales', podemos adjuntar restricciones a miembros hijos de nuestros candidatos.



    Entonces un candidato necesita ser de tipo Piloto y tener un miembro llamado 'name' que sea igual a la cadena dada para ser aceptada por el resultado.

    Nótese que la restricción de clase no es requerida: Si la sacamos, preguntaríamos por todos los objetos que contienen un miembro 'name' con el valor dado. Aunque en la mayoría de los casos esto no será el comportamiento deseado.

    Encontrar un piloto por los puntos exactos es análogo, vamos a tener que cruzar la línea que divide los objetos de las primitivas en Java.


    [retrievePilotByExactPoints]
    Query query=db.query();
    query.constrain(Pilot.class);
    query.descend("points").constrain(new Integer(100));
    ObjectSet result=query.execute();
    listResult(result);



    3.2. Consultas avanzadas


    Hay ocasiones en las que no queremos consultar por los valores exactos de un campo, sino por rangos de valores, objetos que no contienen valores dados, etc. Esta funcionalidad es provista por la API de Restricciones (Constraint API).

    Primero, hagamos una consulta negada para encontrar todos los pilotos que no son Michael Schumacher:


    [retrieveByNegation]
    Query query=db.query();
    query.constrain(Pilot.class);
    query.descend("name").constrain("Michael Schumacher").not();
    ObjectSet result=query.execute();
    listResult(result);


    Donde está la negación, puede haber también otros operadores booleanos.


    [retrieveByConjunction]
    Query query=db.query();
    query.constrain(Pilot.class);
    Constraint constr=query.descend("name")
            .constrain("Michael Schumacher");
    query.descend("points")
            .constrain(new Integer(99)).and(constr);
    ObjectSet result=query.execute();
    listResult(result);



    [retrieveByDisjunction]
    Query query=db.query();
    query.constrain(Pilot.class);
    Constraint constr=query.descend("name")
            .constrain("Michael Schumacher");
    query.descend("points")
            .constrain(new Integer(99)).or(constr);
    ObjectSet result=query.execute();
    listResult(result);


    Podemos también restringir a una comparación por un valor dado.


    [retrieveByComparison]
    Query query=db.query();
    query.constrain(Pilot.class);
    query.descend("points")
            .constrain(new Integer(99)).greater();
    ObjectSet result=query.execute();
    listResult(result);


    La API de consultas también permite consultar por valores por omisión de un campo. 

    [retrieveByDefaultFieldValue]
    Pilot somebody=new Pilot("Somebody else",0);
    db.set(somebody);
    Query query=db.query();
    query.constrain(Pilot.class);
    query.descend("points").constrain(new Integer(0));
    ObjectSet result=query.execute();
    listResult(result);
    db.delete(somebody);


    También es posible hacer que db4o ordene los resultados.


    [retrieveSorted]
    Query query=db.query();
    query.constrain(Pilot.class);
    query.descend("name").orderAscending();
    ObjectSet result=query.execute();
    listResult(result);
    query.descend("name").orderDescending();
    result=query.execute();
    listResult(result);


    Todas estas técnicas pueden ser combinadas arbitrariamente por supuesto. Inténtelo por favor.

    Para prepararnos para el próximo capítulo, limpiemos la base de datos.


    [clearDatabase]
    ObjectSet result=db.get(new Pilot(null,0));
    while(result.hasNext()) {
        db.delete(result.next());
    }



    3.3. Conclusión


    Ahora sabemos como construir consultas arbitrariamente complejas. Pero nuestro dominio de modelo no es complejo en absoluto, solo consiste de una clase. Echemos una mirada a la forma en que db4o maneja asociaciones entre objetos en el próximo capítulo .

    3.4. Fuentes completos



    package com.db4o.f1.chapter1;

    import com.db4o.Db4o;
    import com.db4o.ObjectContainer;
    import com.db4o.ObjectSet;
    import com.db4o.f1.Util;
    import com.db4o.query.Constraint;
    import com.db4o.query.Query;


    public class QueryExample extends Util {
        public static void main(String[] args) {
            ObjectContainer db=Db4o.openFile(Util.YAPFILENAME);
            try {
                storeFirstPilot(db);
                storeSecondPilot(db);
                retrieveAllPilots(db);
                retrievePilotByName(db);
                retrievePilotByExactPoints(db);
                retrieveByNegation(db);
                retrieveByConjunction(db);
                retrieveByDisjunction(db);
                retrieveByComparison(db);
                retrieveByDefaultFieldValue(db);
                retrieveSorted(db);
                clearDatabase(db);
            }
            finally {
                db.close();
            }
        }

        public static void storeFirstPilot(ObjectContainer db) {
            Pilot pilot1=new Pilot("Michael Schumacher",100);
            db.set(pilot1);
            System.out.println("Stored "+pilot1);
        }

        public static void storeSecondPilot(ObjectContainer db) {
            Pilot pilot2=new Pilot("Rubens Barrichello",99);
            db.set(pilot2);
            System.out.println("Stored "+pilot2);
        }

        public static void retrieveAllPilots(ObjectContainer db) {
            Query query=db.query();
            query.constrain(Pilot.class);
            ObjectSet result=query.execute();
            listResult(result);
        }

        public static void retrievePilotByName(ObjectContainer db) {
            Query query=db.query();
            query.constrain(Pilot.class);
            query.descend("name").constrain("Michael Schumacher");
            ObjectSet result=query.execute();
            listResult(result);
        }
        
        public static void retrievePilotByExactPoints(
                ObjectContainer db) {
            Query query=db.query();
            query.constrain(Pilot.class);
            query.descend("points").constrain(new Integer(100));
            ObjectSet result=query.execute();
            listResult(result);
        }

        public static void retrieveByNegation(ObjectContainer db) {
            Query query=db.query();
            query.constrain(Pilot.class);
            query.descend("name").constrain("Michael Schumacher").not();
            ObjectSet result=query.execute();
            listResult(result);
        }

        public static void retrieveByConjunction(ObjectContainer db) {
            Query query=db.query();
            query.constrain(Pilot.class);
            Constraint constr=query.descend("name")
                    .constrain("Michael Schumacher");
            query.descend("points")
                    .constrain(new Integer(99)).and(constr);
            ObjectSet result=query.execute();
            listResult(result);
        }

        public static void retrieveByDisjunction(ObjectContainer db) {
            Query query=db.query();
            query.constrain(Pilot.class);
            Constraint constr=query.descend("name")
                    .constrain("Michael Schumacher");
            query.descend("points")
                    .constrain(new Integer(99)).or(constr);
            ObjectSet result=query.execute();
            listResult(result);
        }

        public static void retrieveByComparison(ObjectContainer db) {
            Query query=db.query();
            query.constrain(Pilot.class);
            query.descend("points")
                    .constrain(new Integer(99)).greater();
            ObjectSet result=query.execute();
            listResult(result);
        }

        public static void retrieveByDefaultFieldValue(
                        ObjectContainer db) {
            Pilot somebody=new Pilot("Somebody else",0);
            db.set(somebody);
            Query query=db.query();
            query.constrain(Pilot.class);
            query.descend("points").constrain(new Integer(0));
            ObjectSet result=query.execute();
            listResult(result);
            db.delete(somebody);
        }
        
        public static void retrieveSorted(ObjectContainer db) {
            Query query=db.query();
            query.constrain(Pilot.class);
            query.descend("name").orderAscending();
            ObjectSet result=query.execute();
            listResult(result);
            query.descend("name").orderDescending();
            result=query.execute();
            listResult(result);
        }

        public static void clearDatabase(ObjectContainer db) {
            ObjectSet result=db.get(new Pilot(null,0));
            while(result.hasNext()) {
                db.delete(result.next());
            }
        }
    }





    --
    generated by
    Doctor courtesy of db4objecs Inc.