El gestor de entidades convierte todos los objetos de entidad en objetos de tuple antes de que se almacenen en una correlación de WebSphere eXtreme Scale. Cada entidad tiene un tuple de clave y tuple de valor. Este par de clave-valor se almacena en la correlación asociada de eXtreme Scale para la entidad. Al utilizar una correlación eXtreme Scale con un cargador, éste debe interactuar con los objetos de tuple.
eXtreme Scale contiene plug-ins de cargador que simplifican la integración con las bases de datos relacionales. Los cargadores JPA (Java Persistence) utilizan una Java Persistence API para interactuar con la base de datos y crear los objetos de entidad. Los cargadores JPA son compatibles con las entidades de eXtreme Scale.
Un tuple contiene información sobre los atributos y las asociaciones de una entidad. Los valores primitivos se almacenan mediante derivadores primitivos. Otros tipos de objeto admitidos se almacenan con su formato nativo. Las asociaciones a otras entidades se almacenan como una colección de objetos de tuples de clave que representan las claves de las entidades de destino.
Cada atributo o asociación se almacena mediante un índice basado en cero. Puede recuperar el índice de cada atributo utilizando los métodos getAttributePosition o getAssociationPosition. Después de que se recupere la posición, permanecerá sin cambios durante el ciclo de vida de eXtreme Scale. La posición puede cambiar cuando se reinicie eXtreme Scale. Los métodos setAttribute, setAssociation y setAssociations se utilizan para actualizar los elementos en el tuple.
El siguiente ejemplo explica de forma adicional cómo procesar tuples. Para obtener más información sobre cómo definir entidades para este ejemplo, consulte Guía de aprendizaje del gestor de entidades: esquema de entidades Order. WebSphere eXtreme Scale se ha configurado para utilizar cargadores con cada una de las entidades. De forma adicional, sólo se toma la entidad Order y esta entidad específica tiene una relación de muchos a uno con la entidad Customer. El nombre de atributo es customer, y tiene una relación de uno a muchos con la entidad OrderLine.
Utilice Projector para crear automáticamente objetos Tuple de las entidades. La utilización de Projector puede simplificar los cargadores cuando se utiliza un programa de utilidad de correlaciones de objetos relacionales como, por ejemplo, Hibernate o JPA.
@Entity
public class Order
{
@Id String orderNumber;
java.util.Date date;
@OneToOne(cascade=CascadeType.PERSIST) Customer customer;
@OneToMany(cascade=CascadeType.ALL, mappedBy="order") @OrderBy("lineNumber") List<OrderLine> lines;
}
@Entity
public class Customer {
@Id String id;
String firstName;
String surname;
String address;
String phoneNumber;
}
@Entity
public class OrderLine
{
@Id @ManyToOne(cascade=CascadeType.PERSIST) Order order;
@Id int lineNumber;
@OneToOne(cascade=CascadeType.PERSIST) Item item;
int quantity;
double price;
}
Una clase OrderLoader que implementa la interfaz Loader se muestra en el siguiente código. El siguiente ejemplo presupone que se ha definido un plug-in TransactionCallback asociado.
public class OrderLoader implements com.ibm.websphere.objectgrid.plugins.Loader {
private EntityMetadata entityMetaData;
public void batchUpdate(TxID txid, LogSequence sequence)
throws LoaderException, OptimisticCollisionException {
...
}
public List get(TxID txid, List keyList, boolean forUpdate)
throws LoaderException {
...
}
public void preloadMap(Session session, BackingMap backingMap)
throws LoaderException {
this.entityMetaData=backingMap.getEntityMetadata();
}
}
La variable de la instancia entityMetaData se ha inicializado durante la llamada al método preLoadMap desde eXtreme Scale. La variable entityMetaData no es nula si la correlación se ha configurado para utilizar entidades. De lo contrario, el valor es nulo.
El método batchUpdate proporciona la capacidad de saber qué acción tiene previsto realizar la aplicación. Basándose en una operación insertar, actualizar o suprimir, se puede abrir una conexión con la base de datos y el trabajo realizado. Puesto que la clave y los valores son del tipo Tuple, se deben transformar de forma que los valores tengan sentido en la sentencia SQL.
La tabla ORDER se creó con la siguiente definición DLL (lenguaje de definición de datos), tal como se muestra en el código siguiente:
CREATE TABLE ORDER (ORDERNUMBER VARCHAR(250) NOT NULL, DATE TIMESTAMP, CUSTOMER_ID VARCHAR(250))
ALTER TABLE ORDER ADD CONSTRAINT PK_ORDER PRIMARY KEY (ORDERNUMBER)
El código siguiente muestra cómo convertir un tuple en un objeto:
public void batchUpdate(TxID txid, LogSequence sequence)
throws LoaderException, OptimisticCollisionException {
Iterator iter = sequence.getPendingChanges();
while (iter.hasNext()) {
LogElement logElement = (LogElement) iter.next();
Object key = logElement.getKey();
Object value = logElement.getCurrentValue();
switch (logElement.getType().getCode()) {
case LogElement.CODE_INSERT:
1) if (entityMetaData!=null) {
// El pedido sólo tiene una clave orderNumber
2) String ORDERNUMBER=(String) getKeyAttribute("orderNumber", (Tuple) key);
// Obtener el valor de fecha
3) java.util.Date unFormattedDate = (java.util.Date) getValueAttribute("date",(Tuple)value);
// Los valores son 2 asociaciones. Permite el proceso de clientes porque
// la tabla contiene customer.id como clave primaria
4) Object[] keys= getForeignKeyForValueAssociation("customer","id",(Tuple) value);
//Order para Customer es M para 1. Sólo puede haber 1 clave
5) String CUSTOMER_ID=(String)keys[0];
// analizar variable unFormattedDate y darle formato para la base de datos como formattedDate
6) String formattedDate = "2007-05-08-14.01.59.780272"; // formateado para DB2
// Por último, la sentencia SQL para insertar el registro
7) //INSERT INTO ORDER (ORDERNUMBER, DATE, CUSTOMER_ID) VALUES(ORDERNUMBER,formattedDate, CUSTOMER_ID)
}
break;
case LogElement.CODE_UPDATE:
break;
case LogElement.CODE_DELETE:
break;
}
}
}
// devuelve el valor al atributo según está almacenado en el tuple de clave
private Object getKeyAttribute(String attr, Tuple key) {
//obtener metadatos de clave
TupleMetadata keyMD = entityMetaData.getKeyMetadata();
//obtener posición del atributo
int keyAt = keyMD.getAttributePosition(attr);
if (keyAt > -1) {
return key.getAttribute(keyAt);
} else { // attribute undefined
throw new IllegalArgumentException("Invalid position index for "+attr);
}
}
// devuelve el valor al atributo según está almacenado en el tuple de valor
private Object getValueAttribute(String attr, Tuple value) {
//similar a la operación anterior, excepto que se trabaja con metadatos de valor
TupleMetadata valueMD = entityMetaData.getValueMetadata();
int keyAt = valueMD.getAttributePosition(attr);
if (keyAt > -1) {
return value.getAttribute(keyAt);
} else {
throw new IllegalArgumentException("Invalid position index for "+attr);
}
}
// devuelve una matriz de claves que se refiere a la asociación.
private Object[] getForeignKeyForValueAssociation(String attr, String fk_attr, Tuple value) {
TupleMetadata valueMD = entityMetaData.getValueMetadata();
Object[] ro;
int customerAssociation = valueMD.getAssociationPosition(attr);
TupleAssociation tupleAssociation = valueMD.getAssociation(customerAssociation);
EntityMetadata targetEntityMetaData = tupleAssociation.getTargetEntityMetadata();
Tuple[] customerKeyTuple = ((Tuple) value).getAssociations(customerAssociation);
int numberOfKeys = customerKeyTuple.length;
ro = new Object[numberOfKeys];
TupleMetadata keyMD = targetEntityMetaData.getKeyMetadata();
int keyAt = keyMD.getAttributePosition(fk_attr);
if (keyAt < 0) {
throw new IllegalArgumentException("Invalid position index for " + attr);
}
for (int i = 0; i < numberOfKeys; ++i) {
ro[i] = customerKeyTuple[i].getAttribute(keyAt);
}
return ro;
}
La demarcación y el acceso de la transacción a la base de datos se cubre en Escribir un cargador.
Si no se encuentra la clave en la memoria caché, llame al método get en el plug-in Loader para encontrar la clave.
public List get(TxID txid, List keyList, boolean forUpdate) throws LoaderException {
System.out.println("OrderLoader: Get called");
ArrayList returnList = new ArrayList();
1) if (entityMetaData != null) {
int index=0;
for (Iterator iter = keyList.iterator(); iter.hasNext();) {
2) Tuple orderKeyTuple=(Tuple) iter.next();
// El pedido sólo tiene una clave orderNumber
3) String ORDERNUMBERKEY = (String) getKeyAttribute("orderNumber",orderKeyTuple);
//Ejecute una consulta para obtener valores de
4) // SELECT CUSTOMER_ID, date FROM ORDER WHERE ORDERNUMBER='ORDERNUMBERKEY'
5) //1) Clave foránea: CUSTOMER_ID
6) //2) fecha
// Se presupone que éstos se devuelven como
7) String CUSTOMER_ID = "C001"; // Se presupone recuperación e inicialización
8) java.util.Date retrievedDate = new java.util.Date();
// Se presupone que esta fecha refleja la de la base de datos
// A continuación, se deben convertir estos datos en un tuple antes de devolver
//crear un tuple de valor
9) TupleMetadata valueMD = entityMetaData.getValueMetadata();
Tuple valueTuple=valueMD.createTuple();
//añadir objeto retrievedDate a Tuple
int datePosition = valueMD.getAttributePosition("date");
10) valueTuple.setAttribute(datePosition, retrievedDate);
//A continuación se debe añadir la asociación
11) int customerPosition=valueMD.getAssociationPosition("customer");
TupleAssociation customerTupleAssociation =
valueMD.getAssociation(customerPosition);
EntityMetadata customerEMD = customerTupleAssociation.getTargetEntityMetadata();
TupleMetadata customerTupleMDForKEY=customerEMD.getKeyMetadata();
12) int customerKeyAt=customerTupleMDForKEY.getAttributePosition("id");
Tuple customerKeyTuple=customerTupleMDForKEY.createTuple();
customerKeyTuple.setAttribute(customerKeyAt, CUSTOMER_ID);
13) valueTuple.addAssociationKeys(customerPosition, new Tuple[] {customerKeyTuple});
14) int linesPosition = valueMD.getAssociationPosition("lines");
TupleAssociation linesTupleAssociation = valueMD.getAssociation(linesPosition);
EntityMetadata orderLineEMD = linesTupleAssociation.getTargetEntityMetadata();
TupleMetadata orderLineTupleMDForKEY = orderLineEMD.getKeyMetadata();
int lineNumberAt = orderLineTupleMDForKEY.getAttributePosition("lineNumber");
int orderAt = orderLineTupleMDForKEY.getAssociationPosition("order");
if (lineNumberAt < 0 || orderAt < 0) {
throw new IllegalArgumentException(
"Invalid position index for lineNumber or order "+
lineNumberAt + " " + orderAt);
}
15) // SELECT LINENUMBER FROM ORDERLINE WHERE ORDERNUMBER='ORDERNUMBERKEY'
// Se presupone que dos filas de número de línea se devuelven con los valores 1 y 2
Tuple orderLineKeyTuple1 = orderLineTupleMDForKEY.createTuple();
orderLineKeyTuple1.setAttribute(lineNumberAt, new Integer(1));// set Key
orderLineKeyTuple1.addAssociationKey(orderAt, orderKeyTuple);
Tuple orderLineKeyTuple2 = orderLineTupleMDForKEY.createTuple();
orderLineKeyTuple2.setAttribute(lineNumberAt, new Integer(2));// Init Key
orderLineKeyTuple2.addAssociationKey(orderAt, orderKeyTuple);
16) valueTuple.addAssociationKeys(linesPosition, new Tuple[]
{orderLineKeyTuple1, orderLineKeyTuple2 });
returnList.add(index, valueTuple);
index++;
}
}else {
// no admite tuples
}
return returnList;
}
En este tema se ofrecen los pasos para crear tuples, y una descripción de la entidad Order solamente. Siga pasos similares para otras entidades, y todo el proceso unido al plug-in TransactionCallback. Consulte Plug-ins para gestionar los sucesos del ciclo de vida de transacciones si desea más detalles.