DAM-M3-UF6. Persistència a bases de dades OO

De Wiki IES Marianao. Departament Informàtica
La revisió el 19:30, 28 des 2012 per Alex (Discussió | contribucions) (SODA Query API)

Dreceres ràpides: navegació, cerca

torna M3 - Programació

Introducció

Hi ha múltiples maneres de gestionar la persistència des de Java, alguns exemples:


BBDD Relacionals SQL incrustat (Embedded) Per exemple SQLJ Utilitza directament SQL

Molt eficient. Poc usat i amb poc suport (Per exemple Eclipse no)


Intermediari (Driver) Exemples:

JDBC ODBC

Les interfícies són lleugeres, aporten mètodes d'utilitat per facilitar la gestió de les tasques més comuns

Eines específiques Eines d'alt nivell:

Hibernate API de Persistència Java

Afegeixen gran abstracció respecte la base de dades, i per tant independència de la tecnologia.

En general requereixen d'un procés previ de configuració

BBDD OO Llibreries específiques per a cada SGBD OO


En general depèn del tipus de base de dades, les més comuns les BBDD Relacionals.

Bases de dades OO

Aquests tipus de BBDD emmagatzemen objectes (atributs i mètodes). La persistència és doncs molt més directa, no existeixen les limitacions de les BBDD Relacionals. Des del punt de vista del programador és molt més senzill treballar amb aquest tipus de base de dades (Si es programa amb objectes).

Per contra existeixen poques BBDD OO al mercat, en general no s'utilitzen i conceptualment són difícils d'entendre (com s'emmagatzemen les dades? i els mètodes?...)

Cada objecte guardat s'identifica per un OID (Object Identifier), independent de les dades que conté.

ODBMS : Object Database Management System


http://en.wikipedia.org/wiki/Object_database http://en.wikipedia.org/wiki/Comparison_of_object_database_management_systems

db4o - Database 4(for) Objects

db4o és un exemple de les múltiples BBDD OO del mercat

http://www.db4o.com

Algunes de les seves característiques són:

  • De codi obert sota llicència GPL, orientat a Java
  • Senzill d'utilitzar i amb bon rendiment,
  • La base de dades és un únic fitxer
  • Només cal importar una llibreria "db4o-8.0.....-all-java5.jar"


OME (Object Manager Enterprise)

El propi gestor incorpora una utilitat (Plugin per Eclipse) que permet explorar els objectes de la base de dades


OME.png


Vista OME:

  • db4o browser: mostra les classes i els atributs (Botó dret: View All Objects)
  • Property View: Propietats de la BBDD, de les classes i dels objecte (OID), permet crear índexs
  • Build Query: Crear consultes, arrossegant des del Browser
  • Query Results: Mostrar resultat de les consultes i modificar valors

Menú OME

  • Connectar i desconnectar de la Base de dades


Connectar i desconnectar

La connexió es molt simple, només cal indicar el fitxer.

Això genera un objecte ObjectContainer que representa la BBDD.

Per tancar la connexió es crida el mètode close().


    private static final String BBDDFITXER = "DB4Oexemple";

    public static void main(String[] args) {
        new File(BBDDFITXER).delete(); // Obliga a crear nova BBDD cada vegada (Opcional)

        ObjectContainer db = Db4oEmbedded.openFile(Db4oEmbedded.newConfiguration(), BBDDFITXER);
        try {

            // Treballar amb la BBDD

        } finally {
            db.close();
        }
    }


Classe Exemple Inicial

public class Pilot {
    private String name;
    private int points;
    public Pilot(String name,int points) {
        this.name=name;
        this.points=points;
    }
    public int getPoints() {
        return points;
    }
    public void addPoints(int points) {
        this.points+=points;
    }
    public String getName() {
        return name;
    }
    public String toString() {
        return name+"/"+points;
    }
}


Operacions ABM

La inserció i la modificació es realitzen a través del mètode store(object).

// Desar objectes
            Pilot pilot1 = new Pilot("Michael Schumacher", 100);
            db.store(pilot1);

            Pilot pilot2 = new Pilot("Rubens Barrichello", 99);
            db.store(pilot2);

Per modificar un objecte només cal cridar a store(object) després de fer els canvis

            pilot1.addPoints(20);
            db.store(pilot1);


La eliminació amb el mètode delete(object), més endavant veurem que aquí hi ha certes consideracions a tenir en compte.

            db.delete(pilot2);


Consultes

El gestor db4o permet tres tipus de consultes

  • Query By Example (QBE).
  • Native Queries (NQ). Opció recomanada, interface principal de consulta.
  • SODA Query API.

Query By Example (QBE)

Es basa en crear un objecte propotip que s'utilitza d'exemple per a la consulta.

A partir del prototip s'obtenen els objectes que tenen els mateixos valors, per indicar "qualsevol" s'utilitzen els valors per defecte del tipus de l'atribut: 0 - enters, null - objectes, etc..

El resultat es retorna en un ObjectSet (Conjunt) que implementa les interfaces java.util.Collection<T>, java.lang.Iterable<T>, java.util.List<T>

            Pilot proto = new Pilot(null, 0);  // Tots
            ObjectSet<Pilot> result = db.queryByExample(proto);
            System.out.println(result.size());
            for (Pilot p : result) {
                System.out.println(p);
            }


            proto = new Pilot("Michael Schumacher", 0);   // Pilots amb nom "Michael Schumacher"
            result = db.queryByExample(proto);
            System.out.println(result.size());
            Iterator<Pilot> it = result.iterator();
            while (it.hasNext()) {
                System.out.println(it.next());
            }


Native Queries (NQ)

Aquesta és la opció recomanada a la documentació.

Els Inconvenients de QBE són:

  • No es poden utilitzar expressions complexes AND, OR, NOT, >, <, == etc...
  • Es necessari un constructor per a indicar les condicions sobre els atributs


Les consultes NQ:

  • Permeten expressions complexes
  • S'escriuen en el propi llenguatge (Java)
  • Si es possible utilitzen els índexs definits


Les restriccions es creen a partir d'un predicat : Classe Predicate

Aquesta classe només inclou el mètode match(candidat) que retorna l'expressió a avaluar sobre un objecte candidat


A l'exemple següent es mostra com fer una consulta amb anonymous inner classes, en general això no és una bona pràctica perquè no permet reutilitzar codi i és poc clar. Tot i això hi ha situacions on és útil.


            List <Pilot> pilots1 = db.query(new Predicate<Pilot>() {
                public boolean match(Pilot pilot) {
                    return pilot.getPoints() == 100;
                }
            });


També es pot extendre la classe Predicate i sobreescriure el mètode match(candidate)

            class PilotHundredPoints extends Predicate<Pilot> {
                public boolean match(Pilot pilot) {
                    return pilot.getPoints() == 100;
                }
            }

            List <Pilot> pilots2 = db.query(new PilotHundredPoints());

A partir d'aquí es poden fer les consultes tant complexes com calgui

            List <Pilot> pilots3 = db.query(new Predicate<Pilot>() {
                public boolean match(Pilot pilot) {
                    return pilot.getPoints() > 99
                            && pilot.getPoints() < 199
                            || pilot.getName().equals("Rubens Barrichello");
                }
            });

SODA Query API

SODA és l'API de baix nivell per a consultes. Per exemple internament les consultes NQ es transformen en SODA per optimitzar-les abans d'executar-les.

Utilitza strings per identificar els noms dels camps sobre els que posar restriccions

El gestor construeix un graf (arbre) de la consulta amb els nodes i les restriccions

  • node --> Múltiples classes, una classe o un atribut d'una classe
  • constrain --> Afegeix una restricció al node
  • descend --> retorna un node descendent en el graf


            // Tots els objectes
            Query query=db.query();  // Crea SODA query
            query.constrain(Pilot.class);    // Afegeix restricció
            ObjectSet<Pilot> res = query.execute();

            // Tots els objectes amb un valor d'atribut concret
            Query query2=db.query();
            query.constrain(Pilot.class);
            // Afegeix restricció sobre el node descendent (en aquest cas un atribut de tipus primitiu)
            query.descend("name").constrain("Michael Schumacher");
            ObjectSet<Pilot> res2=query.execute();


També permet afegir tot tipus de restriccions: AND, OR, NOT, etc...

            // Negació
            query.descend("name").constrain("Michael Schumacher").not();

            // AND
            query.constrain(Pilot.class);
            Constraint constr=query.descend("name").constrain("Michael Schumacher");
            query.descend("points").constrain(99).and(constr);

            // OR
            query.descend("points").constrain(99).or(constr);

            // Més greater, equal, endsWith ...

            query.descend("points").constrain(99).greater();


Alhora que ordenar el resultat

            // Ordre dels resultats
            query.descend("name").orderAscending();
            query.descend("name").orderDescending();


Associacions