Definición de un esquema de entidad

Un ObjectGrid puede tener varios un número ilimitado de esquemas de entidades lógicas. Las entidades se definen utilizando las clases Java anotadas, XML o una combinación de XML y clases Java. Las entidades definidas se registran con un servidor eXtreme Scale y se enlazan a BackingMaps, índices y otros plug-ins.

Al diseñar un esquema de entidad, debe completar las siguientes tareas:
  1. Definir las entidades y sus relaciones.
  2. Configurar eXtreme Scale.
  3. Registrar las entidades.
  4. Crear aplicaciones basadas en entidades que interactúan con las API EntityManager de eXtreme Scale.

Configuración de esquema de entidad

Un esquema de entidad es un conjunto de entidades y las relaciones entre las entidades. En una aplicación de eXtreme Scale con varias particiones, se aplican las siguientes restricciones y opciones a los esquemas de entidades: Las entidades se registran con una instancia de ObjectGrid antes de que se inicialice. Cada entidad definida debe tener un nombre exclusivo y se enlaza automáticamente a una BackingMap de ObjectGrid con el mismo nombre. El método de inicialización varía en función de la configuración que se utilice:

Configuración de eXtreme Scale local

Si utiliza un ObjectGrid local, puede configurar mediante programación la entidad de esquema. En esta modalidad, puede utilizar los métodos ObjectGrid.registerEntities para registrar clases de entidad anotadas o un archivo de descriptor de metadatos de entidad.

Configuración de eXtreme Scale distribuido

Si utiliza una configuración de eXtreme Scale distribuido, debe proporcionar un archivo de descriptor de metadatos de entidad con el esquema de entidad.

Para obtener más detalles, consulte Gestor de entidades en un entorno distribuido.

Requisitos de la entidad

Los metadatos de entidad se configuran utilizando archivos de clase Java, un archivo XML descriptor de entidad o ambos. Como mínimo, se requiere el XML el descriptor de entidad para identificar qué BackingMaps de eXtreme Scale se deben asociar con entidades. Los atributos persistentes de la entidad y sus relaciones con otras entidades se describen en una clase Java anotada (clase de metadatos de entidad) o en el archivo XML descriptor de entidad. La clase de metadatos de entidad, cuando se especifica, también es utilizada por la API EntityManager interactuar con los datos en la cuadrícula.

Una cuadrícula de eXtreme Scale se puede definir sin proporcionar ninguna clase de entidad. Esto puede ser beneficioso cuando el servidor y el cliente interactúan directamente con los datos de tuple almacenados en las correlaciones subyacentes. Estas entidades se definen completamente en el archivo XML descriptor de entidad y se conocen como entidades sin clase.

Entidades sin clase

Las entidades sin clase son útiles cuando no es posible incluir clases de aplicación en el servidor o en la vía de acceso de clases del cliente. Estas entidades se definen en el archivo XML descriptor de metadatos de entidad, donde el nombre de clase de la entidad se especifica utilizando un identificador de entidad sin clase en el formato siguiente: <identificador de entidad>. El símbolo @ identifica la entidad como entidad sin clase y se utiliza para correlacionar asociaciones entre entidades. Consulte la figura "Metadatos de entidad sin clase" para ver un ejemplo de un archivo XML descriptor de metadatos de entidad con dos entidades sin clase definidas.

Si un servidor o cliente de eXtreme Scale no tienen acceso a las clases, cualquiera de los dos puede seguir utilizando la API EntityManager utilizando entidades sin clase. Entre los casos de uso común se encuentran los siguientes:

  • El contenedor de eXtreme Scale se aloja en un servidor que no permite clases de aplicación en la vía de acceso de clases. En este caso, los clientes pueden seguir accediendo a la cuadrícula utilizando la API EntityManager desde un cliente donde las clases estén permitidas.
  • El cliente de eXtreme Scale no necesita acceso a las clases de entidad porque el cliente utiliza o un cliente que no es Java, como el servicio de datos REST de eXtreme Scale, o el cliente accede a los datos de tuple de la cuadrícula utilizando la API ObjectMap.

Si los metadatos de entidad son compatibles entre el cliente y servidor, se pueden crear metadatos de entidad utilizando clases de metadatos de entidad, un archivo XML, o a ambos.

Por ejemplo, la "clase de entidad mediante programa" de la figura siguiente es compatible con el código de metadatos sin clase de la siguiente sección.

Clase de entidad mediante programa
@Entity
public class Employee {
    @Id long serialNumber;
    @Basic byte[] picture;
    @Version int ver;
    @ManyToOne(fetch=FetchType.EAGER, cascade=CascadeType.PERSIST)
    Department department;
}

@Entity
public static class Department {
    @Id int number;
    @Basic String name;
    @OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL, mappedBy="department")
    Collection<Employee> employees;
}

Campos, claves y versiones sin clase

Tal como se ha mencionado anteriormente, las entidades sin clases se configuran completamente en el archivo descriptor XML de entidad. Las entidades basadas en clases definen sus atributos utilizando campos propiedades y anotaciones Java. Por lo tanto, las entidades sin clases necesitan definir la estructura de claves y atributos en el descriptor XML de entidad con las etiquetas <basic> y <id>.

Metadatos de entidad sin clase
<?xml version="1.0" encoding="UTF-8"?>
	<entity-mappings xmlns="http://ibm.com/ws/projector/config/emd"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://ibm.com/ws/projector/config/emd ./emd.xsd">

<entity class-name="@Employee" name="Employee">
    <attributes>
        <id name="serialNumber" type="long"/>
        <basic name="firstName" type="java.lang.String"/>
        <basic name="picture" type="[B"/>
        <version name="ver" type="int"/>
        	<many-to-one name="department"
            target-entity="@Department"
            fetch="EAGER"">
                	<cascade><cascade-persist/></cascade>
        	</many-to-one>
    </attributes>
	</entity>

<entity class-name="@Department" name="Department" >
    <attributes>
        <id name="number" type="int"/>
        <basic name="name" type="java.lang.String"/>
        <version name="ver" type="int"/>
        	<one-to-many name="employees"
            target-entity="@Employee" 
            fetch="LAZY" 
            mapped-by="department">
            	<cascade><cascade-all/></cascade>
        	</one-to-many>
    </attributes>
</entity>

Observe que cada entidad anterior tiene un elemento <id>. Una entidad sin clase debe tener uno o varios elementos <id> definidos o una asociación de un solo valor que represente la clave para la entidad. Los campos de la entidad se representan mediante elementos <basic>. Los elementos <id>, <version> y <basic> requieren un nombre y un tipo en las entidades sin clase. Consulte la sección siguiente sobre los tipos de atributos soportados para obtener información sobre los tipos soportados.

Requisitos de clases de entidades

Las entidades basadas en clases se identifican mediante la asociación de distintos metadatos con una clase Java. Los metadatos pueden especificarse utilizando anotaciones de Java Platform, Standard Edition 5, un archivo de descriptor de metadatos de entidad o una combinación de anotaciones y el archivo de descriptor. Las clases de entidad deben satisfacer los siguientes criterios: Todas las entidades tienen un nombre y tipo exclusivos. El nombre, si utiliza anotaciones, es el nombre simple (corto) de la clase de forma predeterminada, pero puede alterarse temporalmente utilizando el atributo name de la anotación @Entity.

Atributos persistentes

Los clientes y el gestor de entidades accede al estado persistente de una entidad utilizando campos (variables de instancia) o descriptores de acceso de propiedad de estilo Enterprise JavaBeans. Cada entidad debe definir el acceso basado en el campo o en la propiedad. Las entidades anotadas son de acceso a campos si los campos de clases se anotan y son de acceso a propiedades si el método de obtención de la propiedad es anotado. No se permite una combinación de acceso basado en campos y en propiedades. Si el tipo no se puede determinar automáticamente, se puede utilizar el atributo accessType de la anotación @Entity o XML equivalente para identificar el tipo de acceso.

Campos persistentes
A las variables de instancias de entidades de acceso a campos se accede directamente desde el gestor de entidades y los clientes. Los campos que se marcan con el modificador transient o la anotación transient se ignoran. Los campos persistentes no deben tener modificadores final o static.
Propiedades persistentes
Las entidades de acceso a propiedades se deben adherir a los convenios de firma de JavaBeans para las propiedades de lectura y grabación. Se ignoran los métodos que no siguen los convenios de JavaBeans o que tienen la anotación Transient en el método getter. Para una propiedad de tipo T, debe haber un método de obtención getProperty que devuelva un valor de tipo T y un método de establecimiento vacío setProperty(T). Para los tipos booleanos, el método de obtención puede expresarse como isProperty devolviendo true o false. Las propiedades persistentes no pueden tener el modificador static.
Tipos de atributos soportados
Se da soporte a los siguientes tipos de propiedades y campos persistentes:
  • Los tipos primitivos Java que incluyen derivadores:
  • java.lang.String
  • java.math.BigInteger
  • java.math.BigDecimal
  • java.util.Date
  • java.util.Calendar
  • java.sql.Date
  • java.sql.Time
  • java.sql.Timestamp
  • byte[]
  • java.lang.Byte[]
  • char[]
  • java.lang.Character[]
  • enum
Se da soporte a los tipos de atributos serializables de usuario pero tienen limitaciones de rendimiento, consulta y detección de cambios. Los datos persistentes que no pueden enviarse a través de proxy, como las matrices y objetos serializables de usuario, deben volver a asignarse a la entidad en caso de que se modifiquen.

Los atributos serializables se representan en el archivo XML descriptor de entidad utilizando el nombre de clase del objeto. Si el objeto es una matriz, el tipo de datos se representa utilizando el formato interno Java. Por ejemplo, si un tipo de datos de atributo es java.lang.Byte[][], la representación de serie será [[Ljava.lang.Byte;

Los tipos serializables de usuario deben ceñirse a los procedimientos recomendados siguientes:

  • Implementar métodos de serialización de alto rendimiento. Implementar la interfaz java.lang.Cloneable y el método clone público.
  • Implementar la interfaz java.io.Externalizable.
  • Implementar equals y hashCode

Asociaciones de entidad

Las asociaciones de entidades bidireccionales y unidireccionales, o las relaciones entre entidades se pueden definir como uno con uno, muchos con uno, uno con muchos y muchos con muchos. El gestor de entidades resuelve automáticamente las relaciones de entidades en las referencias de clave adecuadas al almacenar las entidades.

La cuadrícula de eXtreme Scale es la memoria caché de datos y no fuerza la integridad referencial como una base de datos. Aunque las relaciones permiten las operaciones de persistencia y eliminación en cascada para entidades hijas, no detecta ni impone enlaces rotos con los objetos. Cuando se elimina un objeto hijo, la consulta a ese objeto debe eliminarse del padre.

Si define una asociación bidireccional entre dos entidades, debe identificar el propietario de la relación. En una asociación a muchos, el lado de muchos de la relación siempre es el lado propietario. Si la propiedad no puede determinarse automáticamente, se debe especificar el atributo mappedBy de la anotación o el equivalente XML. El atributo mappedBy identifica el campo en la entidad de destino que es el propietario de la relación. Este atributo también ayuda a identificar los campos relacionados donde hay varios atributos del mismo tipo y cardinalidad.

Asociaciones con un solo valor

Las asociaciones de uno con uno o de muchos con uno se indican utilizando las anotaciones@OneToOne y @ManyToOne o los atributos XML equivalentes. El tipo de entidad de destino lo determina el tipo de atributo. El ejemplo siguiente define una asociación unidireccional entre Person y Address. La entidad Customer tiene una referencia a una entidad Address. En este caso, la asociación también podría ser muchos con uno dado que no hay ninguna relación inversa.
@Entity
public class Customer {
  @Id id;
  @OneToOne Address homeAddress;
}

@Entity
public class Address{
  @Id id
  @Basic String city;
}
Para especificar una relación bidireccional entre las clases Customer y Address, añada una referencia a la clase Customer desde la clase Address y añada la anotación adecuada para tachar el lado inverso de la relación. Dado que esta asociación es uno con uno, debe especificar un propietario de la relación utilizando el atributo mappedBy en la anotación @OneToOne.
@Entity
public class Address{
  @Id id
  @Basic String city;
  @OneToOne(mappedBy="homeAddress") Customer customer;
}

Asociaciones valoradas por colecciones

Las asociaciones uno con muchos y muchos con muchos se indican utilizando las anotaciones @OneToMany y @ManyToMany o atributos XML equivalentes. Todas las relaciones de muchos se representan utilizando los tipos: java.util.Collection, java.util.List o java.util.Set. El tipo de entidad de destino se determina por el tipo genérico de Collection, List o Set, o utilizando de forma explícita el atributo targetEntity en la anotación @OneToMany o @ManyToMany (o XML equivalente).
En el ejemplo anterior, no es práctico tener un objeto de dirección por cada cliente porque es posible que muchos clientes compartan una dirección o puedan tener varias direcciones. Esta situación se resuelve mejor utilizando una asociación de muchos:
@Entity
public class Customer {
  @Id id;
  @ManyToOne Address homeAddress;
  @ManyToOne Address workAddress;
}

@Entity
public class Address{
  @Id id
  @Basic String city;
  @OneToMany(mappedBy="homeAddress") Collection<Customer> homeCustomers;


  @OneToMany(mappedBy="workAddress", targetEntity=Customer.class) 
		Collection workCustomers;
}
En este ejemplo, existen dos relaciones distintas entre las mismas entidades: una relación de dirección particular y de trabajo. Se utiliza una colección no genérica para el atributo workCustomers para demostrar cómo utilizar el atributo targetEntity cuando no hay genéricos disponibles.

Asociaciones sin clase

Las asociaciones de entidad sin clase se definen en el archivo XML descriptor de metadatos de entidad de modo similar a como se definen las asociaciones basadas en clases. La única diferencia es que, en lugar de la entidad de destino que apunta a una clase real, apunta al identificador de entidad sin clase utilizado para el nombre de clase de la entidad.

A continuación se muestra un ejemplo:

<many-to-one name="department" target-entity="@Department" fetch="EAGER">
      	<cascade><cascade-all/></cascade>
	</many-to-one>
<one-to-many name="employees" target-entity="@Employee" fetch="LAZY">
      	<cascade><cascade-all/></cascade>
	</one-to-many>

Claves primarias

Todas las entidades deben tener una clave primaria, que puede ser una clave simple (un solo atributo) o compuesta (varios atributos). Los atributos de clave se indican utilizando la anotación ID o se definen en el archivo de descriptor XML de entidad. Los atributos de clave tienen los siguientes requisitos: Las claves primarias compuestas pueden, de forma opcional, definir una clase de clave primaria. Una entidad se asocia a una clase de clave primaria utilizando la anotación @IdClass o el archivo de descriptor XML de entidad. Una anotación @IdClass resulta útil conjuntamente con el método EntityManager.find.
Las clases de claves primarias tienen los siguientes requisitos:
  • Deben ser públicas con un constructor sin argumentos.
  • El tipo de acceso de la clase de clave primaria lo determina la entidad que declara la clase de clave primaria.
  • Si es acceso a propiedades, las propiedades de la clave primaria deben ser públicas o protegidas.
  • Las propiedades o campos de claves primarias deben coincidir con los nombres y tipos de los atributos de claves definidas en la entidad que hace la referencia.
  • Las clases de claves primarias deben implementar los métodos equals y hashCode.
A continuación se muestra un ejemplo:
@Entity
@IdClass(CustomerKey.class)
public class Customer {
    @Id @ManyToOne Zone zone;
    @Id int custId;
    String name;
    ...
}

@Entity
public class Zone{
    @Id String zoneCode;
    String name;
}

public class CustomerKey {
    Zone zone;
    int custId;

    public int hashCode() {...}
    public boolean equals(Object o) {...}
}

Claves primarias sin clase

Las entidades sin clase deben cualquiera tener al menos un elemento <id> o una asociación en el archivo XML con el atributo id=true. Un ejemplo de ambos casos sería el siguiente:

<id name="serialNumber" type="int"/>
<many-to-one name="department" target-entity="@Department" id="true">
	<cascade><cascade-all/></cascade>
</many-to-one>
Recuerde:
La etiqueta XML <id-class> no se soporta para las entidades sin clase.

Proxies de entidad e intercepción de campos

Las clases de entidad y los tipos de atributos soportados mutables se amplían mediante clases de proxy para entidades de acceso a propiedades y se han mejorado mediante códigos de bytes para entidades de acceso a campos de Java Development Kit (JDK) 5. Cualquier acceso a la entidad, incluso por los métodos de negocios internos y los métodos equals, deben utilizar los métodos de acceso a propiedades o campos adecuados.

Los interceptores de proxies y campos se utilizan para permitir al gestor de entidades realizar un seguimiento del estado de la entidad, determinar si la entidad ha cambiado y mejorar el rendimiento. Los interceptores de campos sólo están disponibles en plataformas de Java SE 5 cuando se configura el agente de instrumentación de entidad.

Atención: al utilizar entidades de acceso a propiedades, el método equals debe utilizar el operador instanceof para comparar la instancia actual con el objeto de entrada. Toda la introspección del objeto de destino debe ser a través de las propiedades del objeto y no de los propios campos, ya que la instancia de objeto será el proxy.