Un FetchPlan es la estrategia que el gestor de entidades utiliza para recuperar los objetos asociados si la aplicación tiene que acceder a las relaciones.
Supongamos por ejemplo que la aplicación tiene dos entidades: Department (Departamento) y Employee (Empleado). La relación entre la entidad Department y la entidad Employee es una relación bidireccional de uno a muchos: Un departamento tiene muchos empleados y un empleado pertenece a un solo departamento. Ya que la mayor parte de las veces en que se capte la entidad Department es probable que se capten sus empleados, el tipo de captación de esta relación de uno a muchos se define como EAGER.
A continuación se ofrece un fragmento de código de la clase Department.
@Entity
public class Department {
@Id
private String deptId;
@Basic
String deptName;
@OneToMany(fetch = FetchType.EAGER, mappedBy="department", cascade = {CascadeType.PERSIST})
public Collection<Employee> employees;
}
En un entorno distribuido cuando una aplicación llama a em.find(Department.class, "dept1") para buscar una entidad Department con la clave "dept1", esta operación de búsqueda obtendrá la entidad Department y todas sus relaciones captadas de tipo EAGER. En el caso del fragmento de código anterior, estos son todos los empleados del departamento "dept1".
Antes de WebSphere eXtreme Scale 6.1.0.5, la recuperación de una entidad Department y N entidades Employee incurría en N+1 trayectos cliente-servidor porque el cliente recuperaba una sola entidad por trayecto cliente-servidor. Puede mejorar el rendimiento si recupera estas N+1 entidades en un solo trayecto.
Un plan de captación se puede utilizar para personalizar cómo captar relaciones EAGER personalizando la profundidad máxima de las relaciones. La profundidad de captación sustituye las relaciones EAGER con una profundidad superior a la especificada por relaciones LAZY. De forma predeterminada, la profundidad de captación es la profundidad de captación máxima. Esto significa que se recuperarán todas las relaciones EAGER de todos los niveles navegables mediante EAGER desde la entidad raíz. Una relación EAGER es navegable mediante EAGER desde una entidad raíz si y sólo si todas las relaciones que se inician desde la entidad raíz a ella están configuradas como captadas mediante EAGER.
En el ejemplo anterior, la entidad Employee es navegable mediante EAGER desde la entidad Department porque la relación Department-Employee está configurada como captada mediante EAGER.
Si la entidad Employee tiene otra relación EAGER con una entidad Address, por ejemplo, entonces la entidad Address también será navegable mediante EAGER desde la entidad Department. Sin embargo, si las relaciones Department-Employee se configuraron como de captación LAZY, entonces la entidad ADDRESS no es navegable mediante EAGER desde la entidad Department porque la relación Department-Employee rompe la cadena de captación EAGER.
Se puede recuperar un objeto FetchPlan desde la instancia de EntityManager. La aplicación puede utilizar el método setMaxFetchDepth para cambiar la profundidad de captación máxima.
Un plan de captación está asociado con una instancia de EntityManager. El plan de captación se aplica a cualquier operación de captación, más concretamente como se indica a continuación.
El objeto FetchPlan es mutable. Una vez cambiado, el valor cambiado se aplicará a las operaciones de captación ejecutadas posteriormente.
Un plan de captación es importante para un despliegue distribuido porque decide si las entidades de relación captadas mediante EAGER se recuperan con la entidad raíz en un solo trayecto cliente-servidor o más de uno.
Continuando con el ejemplo anterior, considere ahora que el plan de captación tiene la profundidad máxima definida como infinita. En este caso, cuando una aplicación llama a em.find(Department.class, "dept1") para encontrar una entidad Department, esta operación de búsqueda obtendrá una entidad Department y N entidades Employee en un solo trayecto cliente-servidor. Sin embargo, para un plan de captación con una profundidad de captación máximo definida como cero, sólo se recuperará del servidor el objeto Department, mientras que las entidades Employee se recuperan del servidor sólo cuando se accede a la colección de empleados del objeto Department.
Dispone de varios planes de captación diferentes según sus necesidades, que se explican en las secciones siguientes.
Impacto sobre una cuadrícula distribuida
En un entorno de cliente-servidor, si se utiliza un plan de captación de profundidad infinita, entonces se recuperarán todas las relaciones que sean navegables mediante EAGER desde la entidad raíz en un solo trayecto cliente-servidor.
Ejemplo: Si la aplicación está interesada en todas las entidades Address de todos los empleados de un determinado departamento, utiliza el plan de captación de profundidad infinita para recuperar todas las entidades Address asociadas. El código siguiente sólo incurre en un trayecto cliente-servidor.
em.getFetchPlan().setMaxFetchDepth(FetchPlan.DEPTH_INFINITE);
tran.begin();
Department dept = (Department) em.find(Department.class, "dept1");
// hacer algo con el objeto Address.
for (Employee e: dept.employees) {
for (Address addr: e.addresses) {
// hacer algo con las direcciones.
}
}
tran.commit();
En un entorno de cliente-servidor, si se utiliza un plan de captación cero, entonces sólo se recuperará la entidad raíz en el primer trayecto cliente-servidor. Todas las relaciones EAGER se tratan como si fueran LAZY.
Ejemplo: En este ejemplo, la aplicación sólo está interesada en el atributo de la entidad Department (Departamento). No necesita acceder a sus empleados, de modo que la aplicación define 0 como profundidad del plan de captación.
Session session = objectGrid.getSession();
EntityManager em = session.getEntityManager();
EntityTransaction tran = em.getTransaction();
em.getFetchPlan().setMaxFetchDepth(0);
tran.begin();
Department dept = (Department) em.find(Department.class, "dept1");
// hacer algo con el objeto dept.
tran.commit();
Un plan de captación con profundidad k- tiene su profundidad de captación máxima definida como k.
En un entorno cliente-servidor de eXtreme Scale, si se utiliza un plan de captación de profundidad k-, entonces todas las relaciones EAGER navegables de la entidad raíz dentro de k pasos se recuperarán en el primer trayecto cliente-servidor.
El plan de captación de profundidad infinita (k = infinidad) y el plan de captación de profundidad cero (k = 0) son sólo dos ejemplos del plan de captación de profundidad k-.
Para continuar ampliando el ejemplo anterior, supongamos que hay otra relación EAGER de la entidad Employee (Empleado) a la Address (Dirección). Si el plan de captación tiene la profundidad de captación máxima definida como 1, entonces la operación em.find(Department.class, "dept1") recuperará la entidad Department y todas sus entidades Employee en un solo trayecto cliente-servidor. No obstante, las entidades Address no se recuperarán porque no son navegables mediante EAGER a la entidad Department con 1 solo paso, sino en 2 pasos.
Si utiliza un plan de captación con una profundidad definida como 2, entonces la operación em.find(Department.class, y "dept1") recuperará la entidad Department y todas sus entidades Employee, y todas las entidades Address asociadas con las entidades Employee en un solo trayecto cliente-servidor.
Si ejecuta una consulta de entidad, también puede utilizar un plan de captación para personalizar la recuperación de relaciones.
Por ejemplo, el resultado de la consulta SELECT d FROM Department d WHERE "d.deptName='Department'" tiene una relación con la entidad Department. Observe que la profundidad del plan de captación empieza con la asociación del resultado de la consulta: En este caso, la entidad Department, y no el propio resultado de la consulta. Es decir, la entidad Department está en el nivel de profundidad de captación 0. Por lo tanto, un plan de captación con una profundidad de captación máxima de 1 recuperará la entidad Department y sus entidades Employee en un solo trayecto cliente-servidor.
Ejemplo: En este ejemplo, la profundidad del plan de captación se define como 1, de modo que la entidad Department y sus entidades Employee se recuperan en un trayecto cliente-servidor, pero las entidades Address no se recuperarán en el mismo trayecto.
De forma predeterminada, todas las relaciones navegables mediante EAGER desde la entidad raíz se recuperarán en un solo trayecto cliente-servidor. Esto puede mejorar el rendimiento si se van a utilizar todas las relaciones. Sin embargo, en ciertos escenarios de uso, no se utilizan todas las relaciones navegables mediante EAGER desde la entidad raíz, de modo que incurren tanto en una sobrecarga de tiempo de ejecución como de ancho de banda al recuperar las entidades no utilizadas.
Para estos casos, la aplicación puede definir un número pequeño como profundidad de captación máxima para disminuir la profundidad de las entidades que se deben recuperar realizando todas las relaciones EAGER después de dicha profundidad LAZY. Este valor puede aumentar el rendimiento.
Siguiendo aún más con el ejemplo Department-Employee-Address, de forma predeterminada, se recuperarán todas las entidades Address asociadas con empleados del departamento "dept1" cuando se llame a em.find(Department.class, "dept1"). Si la aplicación no utiliza entidades Address, puede definir la profundidad de captación máxima como 1, de modo que las entidades Address no se recuperarán con la entidad Department.