Persistencia de Objetos Java Utilizando JDO

Puede encontrar la versión original de este artículo en Inglés en:

http://www.devx.com/

Introducción

Para la mayoría de las aplicaciones, almacenar y recuperar información implica alguna forma de interacción con una base de datos relacional. Esto ha representado un problema fundamental para los desarrolladores porque algunas veces el diseño de datos relacionales y los ejemplares orientados a objetos comparten estructuras de relaciones muy diferentes dentro de sus respectivos entornos.

Las bases de datos relacionales están estructuradas en una configuración tabular y los ejemplares orientados a objetos normalmente están relacionados en forma de árbol. Esta 'diferencia de impedancia' ha llevado a los desarrolladores de varias tecnologías de persistencia de objetos a intentar construir un puente entre el mundo relacional y el mundo orientado a objetos. El API Java Data Objects (JDO) proporciona otra forma más de eliminar esta diferencia.

Introducción a la Persistencia de Objetos

Persistir objetos Java en una base de datos relacional es un reto único que implica serializar un arbol de objetos Java en una base de datos de estructura tabular y viceversa. Este reto actualmente está siendo corregido por varias herramientas diferentes. La mayoría de estas herramientas permite a los desarrolladores instruir a los motores de persistencia de cómo convertir objetos Java a columnas/registros de la base de datos y al revés. Esencial para este esfuerzo es la necesidad de mapear objetos Java a columnas y registros de la base de datos de una forma optimizada en velocidad y eficiencia.

El API Java Data Objects (JDO) proporciona una forma estándar y sencilla de conseguir la persistencia de objetos en la tecnología Java. JDO utiliza una combinación práctica de metadatos XML y bytecodes mejorados para hacer más sencilla la complejidad y al sobrecarga, comparado con otras tecnologías de unión de objetos.

Introducción a JDO

El API JDO, consta sólo de unos pocos interfaces, es uno de los APIs más fáciles de aprender de toda la tecnología existente actualmente para la persistencia de objetos estandarizada. Hay muchas implementaciones de JDO entre las que elegir. La implementación de referencia de JDO la ha puesto Sun a nuestra disposición.

Una razón de la simplicidad de JDO es que permite trabajar con objetos normales de Java (POJOs plain old Java objects) en lugar de con APIs propietarios. JDO corrige el aumento de la persistencia en un paso de mejora de bytecodes posterior a la compilación, así proporciona una capa de abstacción entre el código de la aplicación y el motor de persistencia.

JDO ha recibido ataques por muchas razones, entre las que se incluyen: el modelo de mejora de código debería reemplazarse por un modelo de persistencia transparente; los vendedores podrían perder sus bloqueos propietarios; JDO se solapa demasiado con EJB y CMP. A pesar de estos puntos de resistencia, muchos expertos están tutorizando JDO como una enorme mejora sobre las tendencias actuales de tecnologías objeto-a-datos y datos-a-objeto.

La Aplicación y el Entorno de Ejecución

Utilizaremos la implementación de referencia de JDO que se puede encontrar en http://www.sun.com/software/communitysource/jdo/index.html y JBoss 3.2.3 como entorno de despliegue y ejecución para los siguientes ejemplos. Diseñaré una sencilla aplicación Web que permita crear y recuperar cuentas de usuario utilizando un navegador Web. Las peticiones de los clientes se pasarán a un Servlet Java, que se comunica con un servicio de usuario, que a su vez se comunica con objetos de acceso a datos DAOs basados en JDO, como ilustra la siguiente figura:

El patrón DAO abstrae y encapsula todos los accesos a la fuente de datos. La aplicación tiene un interface DAO, UserDao. La clase de implementación, JDOUserDao, contiene lógica específica de JDO para manejar las tareas de control de datos de un usuario dado.

Configuración de la Capa web

Toda petición HTTP de cliente la maneja un servlet del estilo FrontController embutido dentro de un ejemplar de UserInfoServlet. Este ejemplar convierte la petición en una petición de servicio de negocio y luego llama al servicio de negocio apropiado para su procesamiento. Aquí puede ver el contenido de la clase UserInfoServlet:


package com.jeffhanson.webtier;

import com.jeffhanson.businesstier.model.UserInfo;
import com.jeffhanson.businesstier.ServiceException;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;

public class UserInfoServlet extends HttpServlet {
   
   private void sendErrorResonse(HttpServletResponse res, String errorMsg)
      throws IOException {
      PrintWriter out = res.getWriter();

      out.println("<B>Error: </B>" + errorMsg);
      out.flush();
      out.close();
   }

   protected void doPost(HttpServletRequest req, HttpServletResponse res)
      throws ServletException, IOException {
      doGet(req, res);
   }

   protected void doGet(HttpServletRequest req, HttpServletResponse res)
      throws ServletException, IOException{
      String newUserID = req.getParameter("NewUserID");
      String userID = req.getParameter("userID");
      String state = req.getParameter("state");

      if (newUserID != null && newUserID.length() > 0) {
         String newUserFullName = req.getParameter("NewUserFullName");
         if (newUserFullName == null || newUserFullName.length() == 0) {
            sendErrorResonse(res, "User Full Name must be specified.");
         }
         String newUserAddress = req.getParameter("NewUserAddress");
         if (newUserAddress == null || newUserAddress.length() == 0) {
            sendErrorResonse(res, "User Address must be specified.");
         }
         String newUserCity = req.getParameter("NewUserCity");
         if (newUserCity == null || newUserCity.length() == 0) {
            sendErrorResonse(res, "User City must be specified.");
         }
         String newUserState = req.getParameter("NewUserState");
         if (newUserState == null || newUserState.length() == 0) {
            sendErrorResonse(res, "User State must be specified.");
         }
         String newUserZip = req.getParameter("NewUserZip");
         if (newUserZip == null || newUserZip.length() == 0) {
            sendErrorResonse(res, "User Zip must be specified.");
         }
         res.setContentType("text/html");
         PrintWriter out = res.getWriter();

         try {
            out.println(addUser(newUserID,
                                newUserFullName,
                                newUserAddress,
                                newUserCity,
                                newUserState,
                                newUserZip));
         }
         catch (ServiceException e) {
            throw new ServletException(e.toString());
         }

         out.flush();
         out.close();
      }
      else if (userID != null && userID.length() > 0) {
         res.setContentType("text/html");
         PrintWriter out = res.getWriter();

         try {
            out.println(findSingleUser(userID));
            out.flush();
            out.close();
         }
         catch (ServiceException e) {
            throw new ServletException(e.toString());
         }
      }
      else if (state != null && state.length() > 0) {
         res.setContentType("text/html");
         PrintWriter out = res.getWriter();

         try {
            out.println(findUsersByState(state));
            out.flush();
            out.close();
         }
         catch (ServiceException e) {
            throw new ServletException(e.toString());
         }
      }
      else {
         res.setContentType("text/html");
         PrintWriter out = res.getWriter();
         out.println("No input parameters specified.");
         out.flush();
         out.close();
      }
   }

   private String addUser(String userID,
                          String userFullName,
                          String userAddress,
                          String userCity,
                          String userState,
                          String userZip)
                          throws ServiceException {
      
      UserInfo user = com.jeffhanson.businesstier.UserService.addUser(userID,
                                                         userFullName,
                                                         userAddress,
                                                         userCity,
                                                         userState,
                                                         userZip);
      if (user == null) {
         return "Error creating new user.";
      }

      return "Success creating new user.";
   }

   private String findUsersByState(String state) throws ServiceException {
      String retStr = "";

      UserInfo[] users = com.jeffhanson.businesstier.UserService.getUsersByState(state);
      if (users != null) {
         for (int i = 0; i < users.length; i++) {
            retStr += stringifyUserInfo(users[i]) + "<BR>";
         }
      }
      else {
         retStr = "<para>No users found";
      }
      return retStr;
   }

   private String findSingleUser(String userID) throws ServiceException {
      String retStr = "";
      UserInfo userInfo = com.jeffhanson.businesstier.UserService.getUser(userID);
      if (userInfo != null) {
         retStr = stringifyUserInfo(userInfo);
      }
      else {
         retStr = "<para>User not found";
      }
      return retStr;
   }

   private String stringifyUserInfo(UserInfo userInfo) {
      String retStr;
      StringBuffer strBuf = new StringBuffer();
      strBuf.append("<para>User info: <br>
");
      strBuf.append("User ID: " + userInfo.getId() + "<br>
");
      strBuf.append("User Full Name: " + userInfo.getFullName() + "<br>
");
      strBuf.append("User Address: " + userInfo.getAddress() + "<br>
");
      strBuf.append("User City: " + userInfo.getCity() + "<br>
");
      strBuf.append("User State: " + userInfo.getState() + "<br>
");
      strBuf.append("User Zip: " + userInfo.getZip() + "<br>
");
      retStr = strBuf.toString();
      return retStr;
   }
}

La Capa de Negocio

Toda petición se cliente se convierte a una petición de servicio de negocio y es pasada al servicio de negocio apropiado para su procesamineto Cada objeto de servicio de negocio realiza la lógica de negocio necesaria y hace uso del DAO apropiado para acceder al almacén de datos.

La clase UserService encapsula los métodos para operar sobre objetos UserInfo incluyendo almacenar, borrar, actualizar y recuperar ejemplares de UserInfo. En el siguiente listado puede ver la clase UserService:


package com.jeffhanson.businesstier;

import com.jeffhanson.businesstier.model.UserInfo;
import com.jeffhanson.datatier.JDOUserDAO;

public class UserService {
   public static UserInfo addUser(String id,
                                  String fullName,
                                  String address,
                                  String city,
                                  String state,
                                  String zip)
                                  throws ServiceException {
      UserInfo userInfo = null;

      try {
         JDOUserDAO dao = JDOUserDAO.getInstance();
         userInfo = dao.createUser(id, fullName, address, city, state, zip);
      }
      catch (Exception e) {
         throw new ServiceException(e.toString());
      }
      return userInfo;
   }

   public static UserInfo getUser(String userID) throws ServiceException {
      UserInfo userInfo = null;
      try {
         JDOUserDAO dao = JDOUserDAO.getInstance();
         userInfo = dao.readUser(userID);
      }
      catch (Exception e) {
         throw new ServiceException(e.toString());
      }
      return userInfo;
   }

   public static UserInfo[] getUsersByState(String state) throws ServiceException {
      UserInfo[] users = null;
      try {
         JDOUserDAO dao = JDOUserDAO.getInstance();
         users = dao.readUsersByState(state);
      }
      catch (Exception e) {
         throw new ServiceException(e.toString());
      }
      return users;
   }

   public static void modifyUser(UserInfo userInfo) throws ServiceException {
      try {
         JDOUserDAO dao = JDOUserDAO.getInstance();
         dao.updateUser(userInfo);
      }
      catch (Exception e) {
         throw new ServiceException(e.toString());
      }
   }

   public static void removeUser(UserInfo userInfo) throws ServiceException {
      try {
         JDOUserDAO dao = JDOUserDAO.getInstance();
         dao.deleteUser(userInfo);
      }
      catch (Exception e) {
         throw new ServiceException(e.toString());
      }
   }
}

La clase UserService hace uso de la clase UserInfo que representa a un usuario dado. Aquí puede ver la clase UserInfo:


package com.jeffhanson.businesstier.model;

public class UserInfo {
   private String id = "";
   private String fullName = "";
   private String address = "";
   private String city = "";
   private String state = "";
   private String zip = "";

   public String getId() {
      return id;
   }

   public void setId(String id) {
      this.id = id;
   }

   public String getFullName() {
      return fullName;
   }

   public void setFullName(String fullName) {
      this.fullName = fullName;
   }

   public String getAddress() {
      return address;
   }

   public void setAddress(String address) {
      this.address = address;
   }

   public String getCity() {
      return city;
   }

   public void setCity(String city) {
      this.city = city;
   }

   public String getState() {
      return state;
   }

   public void setState(String state) {
      this.state = state;
   }

   public String getZip() {
      return zip;
   }

   public void setZip(String zip) {
      this.zip = zip;
   }

   public String toString() {
      return "UserInfo { "
             + "ID: " + id
             + ", FullName: " + fullName
             + ", Address: " + address
             + ", City: " + city
             + ", State: " + state
             + ", Zip: " + zip
             +" }";
   }
}

Ficheros de Metadatos JDO

JDO utiliza ficheros de metadatos basados en XML para especificar información relacionada con la persistencia incluyendo las clases que se deberían persistir. El fichero de metadatos puede contener información de persistencia para persistir una sóla clases o uno más paquetes que tienen clases persistentes.

Un fichero de metatados de persistencia JDO puede definir propiedades de persistencia para una clases o para un paquete completo, en uno o más ficheros XML. El nombre del fichero XML para una clase es el nombre de la clase seguido por un sufijo .jdo. Por lo tanto, el fichero de metadatos para la clase UserInfo debería llamarse UserInfo.jdo. Este fichero debe situarse en el mismo directorio que el fichero UserInfo.class. Los metadatos para un paquete completo deben estar contenidos en un fichero llamado package.jdo. Un fichero .jdo para un paquete puede contener información para varias clases y varios sub-paquetes.

El siguiente ejemplo ilustra como se representa la clase UserInfo para la mejora de JDO en el fichero de metadados package.jdo:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jdo PUBLIC
   "-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 1.0//EN"
   "http://java.sun.com/dtd/jdo_1_0.dtd">
<jdo>
   <package name="com.jeffhanson.businesstier.model">

      <class name="UserInfo" identity-type="datastore">

         <field name="id" persistence-modifier="persistent">
            <extension vendor-name="jdori"
                       key="column"
                       value="ID"/>
         </field>

         <field name="fullName" persistence-modifier="persistent">
            <extension vendor-name="jdori"
                       key="column"
                       value="FULLNAME"/>
         </field>

         <field name="address" persistence-modifier="persistent">
            <extension vendor-name="jdori"
                       key="column"
                       value="ADDRESS"/>
         </field>

         <field name="city" persistence-modifier="persistent">
            <extension vendor-name="jdori"
                       key="column"
                       value="CITY"/>
         </field>

         <field name="state" persistence-modifier="persistent">
            <extension vendor-name="jdori"
                       key="column"
                       value="STATE"/>
         </field>

         <field name="zip" persistence-modifier="persistent">
            <extension vendor-name="jdori"
                       key="column"
                       value="ZIP"/>
         </field>

      </class>

   </package>
</jdo>

La Capa de Datos

Toda petición de servicio de negocio se pasa al servicio de negocio apropiado para su procesamiento. Un servicio de negocio realiza la lógica de negocio necesaria y hace uso del DAO apropiado para acceder a los datos. Cada DAO realiza las interacciones necesarias con JDO para poder actúar sobre un almacén de datos dado. El interface UserDAO define los métodos que debe implementar cada DAO:

package com.jeffhanson.datatier;

import com.jeffhanson.businesstier.model.UserInfo;

public interface UserDAO {
   public UserInfo createUser(String id,
                              String fullName,
                              String address,
                              String city,
                              String state,
                              String zip)
                              throws DAOException;

   public UserInfo readUser(String id) throws DAOException;

   public UserInfo[] readUsersByState(String state) throws DAOException;

   public void updateUser(UserInfo userInfo) throws DAOException;

   public void deleteUser(UserInfo userInfo) throws DAOException;
}

La clase JDOUserDAO proporciona una implementación del interface UserDAO, que permitirá acceder a los objetos UserInfo almacenados.

La implementación de referencia de JDO viene con un mecanismo de almacenamiento basado en ficheros llamado fostore. La implementación de la clase JDOUserDAO usa la factoría de manejadores de persistencia fostore. Almacena los datos en dos ficheros llamado fostore.btd u fostore.btx.

Nota del Autor:
JDO soporta un concepto conocido como persistence-by-reachability (persistencia por alcance). Esto hace que los ejemplares temporales de una clase se conviertan en persistentes cuando se remiten si el ejemplar es alcanzado por un ejemplar persistente.

package com.jeffhanson.datatier;

import com.jeffhanson.businesstier.model.UserInfo;

import javax.jdo.*;
import java.util.Properties;
import java.util.Collection;

public class JDOUserDAO implements UserDAO {
   private static JDOUserDAO instance = null;

   public static JDOUserDAO getInstance() {
      if (instance == null) {
         instance = new JDOUserDAO();
      }
      return instance;
   }

   private PersistenceManagerFactory pManagerFactory = null;

   private JDOUserDAO() {
      Properties properties = new Properties();
      properties.put("javax.jdo.PersistenceManagerFactoryClass",
                     "com.sun.jdori.fostore.FOStorePMF");
      properties.put("javax.jdo.option.ConnectionURL",
                     "fostore:FOJDOTestDB");
      properties.put("javax.jdo.option.IgnoreCache", "false");
      properties.put("javax.jdo.option.Multithreaded", "false");
      properties.put("javax.jdo.option.NontransactionalRead", "false");
      properties.put("javax.jdo.option.NontransactionalWrite", "false");
      properties.put("javax.jdo.option.Optimistic", "false");
      properties.put("javax.jdo.option.RetainValues", "false");
      properties.put("javax.jdo.option.RestoreValues", "false");
      pManagerFactory = JDOHelper.getPersistenceManagerFactory(properties);
   }

   public UserInfo createUser(String id,
                              String fullName,
                              String address,
                              String city,
                              String state,
                              String zip)
                              throws DAOException {
      UserInfo user = null;
      user = new UserInfo();
      user.setId(id);
      user.setFullName(fullName);
      user.setAddress(address);
      user.setCity(city);
      user.setState(state);
      user.setZip(zip);
      Transaction transaction = null;
      PersistenceManager pManager = null;
      try {
         // Obtain a Persistence Manager from the Factory Object
         pManager = pManagerFactory.getPersistenceManager();

         // Retrieve a Transaction object from the Persistence Manager
         transaction = pManager.currentTransaction();

         // Begin a transaction
         transaction.begin();

         // Persist the object
         pManager.makePersistent(user);

         // Commit the transaction
         transaction.commit();
      }
      catch(Exception e) {
         if (transaction != null) {
            // Rollback the transaction
            transaction.rollback();
         }
         e.printStackTrace();
      }
      finally {
        // Close the Persistence Manager
        if (pManager != null) {
          pManager.close();
        }
      }
      return user;
   }

   public UserInfo readUser(String id) throws DAOException {
      UserInfo user = null;
      Transaction transaction = null;
      PersistenceManager pManager = null;
      try {
         // Obtain a Persistence Manager from the Factory Object
         pManager = pManagerFactory.getPersistenceManager();

         // Retrieve a Transaction object from the Persistence Manager
         transaction = pManager.currentTransaction();

         // Begin a transaction
         transaction.begin();

         user = new UserInfo();

         // Read the object using JDO navigation
         user.getAddress();
         user.getCity();
         user.getFullName();
         user.getId();
         user.getState();
         user.getZip();

         // Commit the transaction
         transaction.commit();
      }
      catch(Exception e) {
         if (transaction != null) {
            // Rollback the transaction
            transaction.rollback();
         }
         e.printStackTrace();
      }
      finally {
        // Close the Persistence Manager
        if (pManager != null) {
          pManager.close();
        }
      }
      return user;
   }

   public UserInfo[] readUsersByState(String state) throws DAOException {
      UserInfo[] users = null;
      Transaction transaction = null;
      PersistenceManager pManager = null;
      try {
         // Obtain a Persistence Manager from the Factory Object
         pManager = pManagerFactory.getPersistenceManager();

         // Retrieve a Transaction object from the Persistence Manager
         transaction = pManager.currentTransaction();

         // Begin a transaction
         transaction.begin();

         Query query = pManager.newQuery(UserInfo.class,
                                         "state == "" + state + """);

         Collection result = (Collection) query.execute();
         users = (UserInfo[])result.toArray();

         query.close(result);

         // Commit the transaction
         transaction.commit();
      }
      catch(Exception e) {
         if (transaction != null) {
            // Rollback the transaction
            transaction.rollback();
         }
         e.printStackTrace();
      }
      finally {
        // Close the Persistence Manager
        if (pManager != null) {
          pManager.close();
        }
      }
      return users;
   }

   public void updateUser(UserInfo userInfo) throws DAOException {
      UserInfo user = readUser(userInfo.getId());
      Transaction transaction = null;
      PersistenceManager pManager = null;
      try {
         // Obtain a Persistence Manager from the Factory Object
         pManager = pManagerFactory.getPersistenceManager();

         // Retrieve a Transaction object from the Persistence Manager
         transaction = pManager.currentTransaction();

         // Begin a transaction
         transaction.begin();

         // Update the object
         //
         // JDO automatically detects when a field
         // of a persistent object has been modified and marks the field
         // as "dirty." During the commit, the dirty fields of all
         // modified persistent objects are written to the datastore
         // as part of the transaction.
         user.setAddress(userInfo.getAddress());
         user.setCity(userInfo.getCity());
         user.setFullName(userInfo.getFullName());
         user.setState(userInfo.getState());
         user.setZip(userInfo.getZip());

         // Commit the transaction
         transaction.commit();
      }
      catch(Exception e) {
         if (transaction != null) {
            // Rollback the transaction
            transaction.rollback();
         }
         e.printStackTrace();
      }
      finally {
        // Close the Persistence Manager
        if (pManager != null) {
          pManager.close();
        }
      }
   }

   public void deleteUser(UserInfo userInfo) throws DAOException {
      Transaction transaction = null;
      PersistenceManager pManager = null;
      try {
         // Obtain a Persistence Manager from the Factory Object
         pManager = pManagerFactory.getPersistenceManager();

         // Retrieve a Transaction object from the Persistence Manager
         transaction = pManager.currentTransaction();

         // Begin a transaction
         transaction.begin();

         // Delete the object
         pManager.deletePersistent(userInfo);

         // Commit the transaction
         transaction.commit();
      }
      catch(Exception e) {
         if (transaction != null) {
            // Rollback the transaction
            transaction.rollback();
         }
         e.printStackTrace();
      }
      finally {
        // Close the Persistence Manager
        if (pManager != null) {
          pManager.close();
        }
      }
   }
}

El Mejorador de Bytescodes de JDO

Una clase se debe mejorar antes de que sus ejemplares puedan ser manejados por el motor de persistencia de JDO. Un mejorador de bytecodes de JDO añade datos y métodos a las clases para permitir que sus ejemplares sean manejados por el motor de persistencia. Un mejorador de bytecodes lee un fichero .class y lo mejora, sacando un nuevo fichero .class con las funcionalidades de persistencia necesarias.

El mejorador de bytecodes de la implementación de referencia de JDO modifica las clases capaces de persistencia para ejecutarlas en su entorno. Consigue esto haciendo cambios a los bytecodes de la clase. Esto permite sincronizar el estado de un ejemplar de la clase con lo datos del almacén de datos.

Aquí tiene un ejemplo de cómo ejecutar el mejorador de bytecodes de la implementación de referencia de JDO para la aplicación de ejemplo:

java -classpath $JDOHOME/jdo.jar:$JDOHOME/jdori.jar:$JDOHOME/jdori-enhancer.jar: 
com.sun.jdori.enhancer.Main -d ../enhanced -s . -f ./com/jeffhanson/businesstier/model/package.jdo 
./com/jeffhanson/businesstier/model/UserInfo.class

El Lenguaje de Consulta JDO

JDO define un lenguaje de consulta conocido como JDOQL. Este lenguaje está embebido dentro del interface javax.jdo.Query. El PersistenceManager de JDO define los siguientes métodos para construir ejemplares de las clases de implementación de la consulta:

  • Query newQuery();
  • Query newQuery(Class cls);
  • Query newQuery(Class cls, Collection coll);
  • Query newQuery(Class cls, String filter);
  • Query newQuery(Class cls, Collection c, String filter);
  • Query newQuery(Extent ext);
  • Query newQuery(Extent ext, String filter);

El filter se especifica como una expresión booleana que se parece algo a los operadores booleanos de SQL. El resultado de una consulta depende de si la expresión booleanda se evalúa a true por las clases candidatas especificadas. El interface Query proporciona el siguiente método para especificar un filtro:

  • void setFilter(String filter);

Las clases candidatas se pueden especificar utilizando uno de los siguientes métodos del interface Query:

  • void setClass(Class candidateClass);
  • void setCandidates(Collection candidates);
  • void setCandidates(Extent candidates);

El interface Query proporciona métodos para ejecutar una consulta. Los parámetros de conslta se pueden pasar directamente a cualquiera de estos métodos:

  • Object execute(Object param);
  • Object execute(Object param1, Object param2);
  • Object execute(Object param1, Object param2, Object param3);
  • Object executeWithMap(Map paramMap);
  • Object executeWithArray(Object[] paramArray);

El interface Query también proporciona un método para declarar un grupo arbitrario de parámetros separados por comas:

  • void declareParameters(String paramStr);

Este grupo de parámetros debe formatearse como una definición string de las parejas tipo-nombre. Por ejemplo, el siguiente fragmento ilustra un grupo de parámetros para un nombre y una cuenta de usuario:

query.declareParameters("String userName, int accountNumber");

El siguiente código muestra una consulta completa utilizando JDOQL:

String filter = "userInfo.fullName == fullName && "
              + "userInfo.zip.startsWith(userZip)";
Extent extent = persistenceMgr.getExtent(UserInfo.class, true);
Query query = persistenceMgr.newQuery(extent, filter);
query.declareParameters("String city, String state");
Collection result = (Collection)query.execute("Shire", "New York");
Iterator iter = result.iterator();
while(iter.hasNext()) {
   UserInfo user = (UserInfo)iter.next();
   System.out.println("User: " + user.getID());

}
query.close(result);

Las diferencias estructurales entre los árboles de objetos Java y las tablas de las bases de datos relacionales hace que el reto de persistir y recuperar objetos Java en una base de datos relacional sea muy intimidatorio para los desarrolladores. La "diferencia de impedancia" entre las tablas relacionales y los árboles de objetos Java ha llevado al desarrollo de distintas tecnologías de persistencia de objetos Java que intentan unir el mundo relacional y el mundo orientado a objetos. JDO define un marco de trabajo objeto/relacional y un lenguaje de consulta que ayuda a superar el reto de almacenar y recuperar objetos Java de un almacén de datos.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP