Um FetchPlan é a estratégia que o gerenciador de entidade usa para recuperar objetos associados se o aplicativo precisar acessar relacionamentos.
Suponha, por exemplo, que seu aplicativo tenha duas entidades: Department e Employee. O relacionamento entre a entidade Department e a entidade Employee é um relacionamento bidirecional um-para-muitos: Um departamento tem vários funcionários, e um funcionário pertence a um único departamento. Como na maioria das vezes, quando é feita uma busca pela entidade Department, seus Employees provavelmente são buscados, e o tipo de busca desse relacionamento um-para-muitos é configurado como EAGER.
Aqui está um fragmento da classe 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;
}
Em um ambiente distribuído, quando um aplicativo chama em.find(Department.class, "dept1") para localizar uma entidade Department com a chave "dept1", essa operação find obtém a entidade Department e todas as suas relações eager-fetched. No caso do fragmento anterior, elas são todos os funcionários do departamento "dept1".
Antes do WebSphere eXtreme Scale 6.1.0.5, a recuperação de uma entidade Department e N entidades Employee incorria em N+1 trips de cliente-servidor porque o cliente recuperava uma entidade para um trip de cliente-servidor. É possível melhorar o desempenho se você recuperar essas N+1 entidades em um trip.
Um plano de carregamento pode ser utilizado para customizar a forma como você executa um carregamento ansioso de relacionamentos customizando a profundidade máxima dos relacionamentos. A profundidade da busca substitui relações eager maiores do que a profundidade especificada para relações lazy. Por padrão, a profundidade da busca é a profundidade máxima da busca. Isso significa que relacionamentos eager de todos os níveis navegáveis como eager a partir da entidade raiz serão buscados. Um relacionamento EAGER é navegável como eager a partir de uma entidade raiz se, e apenas se, todas as relações começando da entidade raiz para ela forem configuradas como eager-fetched.
No exemplo anterior, a entidade Employee é navegável como eager a partir da entidade Department porque o relacionamento Department-Employee é configurado como eager-fetched.
Se a entidade Employee tiver outro relacionamento eager com uma entidade Address, por exemplo, a entidade Address também será navegável como eager a partir da entidade Department. Entretanto, se os relacionamentos Department-Employee foram configurados como lazy-fetch, a entidade Address não será navegável como eager a partir da entidade Department, pois o relacionamento Department-Employee quebra a cadeia de eager fetch.
Um objeto Plano de Carregamento pode ser recuperado da instância EntityManager. O aplicativo pode utilizar o método setMaxFetchDepth para alterar a profundidade máxima da busca.
Um plano de carregamento é associado a uma instância EntityManager. O plano de carregamento aplica-se a qualquer operação de busca, mais especificamente da seguinte forma.
O objeto Plano de Carregamento é mutável. Após ser alterado, o valor será aplicado às operações de busca executadas posteriormente.
Um plano de carregamento é importante para uma implementação distribuída porque decide se as entidades de relacionamento eager-fetched são recuperadas com a entidade raiz em um trip de cliente/servidor ou em mais de uma.
Continuando com o exemplo anterior, considere que o plano de carregamento tenha profundidade máxima configurada como infinito. Nesse caso, quando o aplicativo chama em.find(Department.class, "dept1") para localizar Department, essa operação find obtém uma entidade Department e N entidades Employee em um trip de cliente/servidor. Entretanto, para um plano de carregamento com profundidade de busca máxima configurada como zero, apenas o objeto Department será recuperado do servidor, enquanto as entidades Employee são recuperadas do servidor apenas quando a coleta de Employees do objeto Department é acessada.
Você tem diferentes planos de carregamentos baseados em seus requisitos, explicados nas seguintes seções.
Impacto em uma grade distribuída
Em um ambiente de cliente/servidor, se um plano de carregamento de profundidade infinita for utilizado, todas as relações navegáveis como eager a partir da entidade raiz serão recuperadas em um trip de cliente/servidor.
Exemplo: Se o aplicativo estiver interessado em todas as entidades Address de todos os employees de um determinado Department, ele utilizará um plano de carregamento de profundidade infinita para recuperar todas as entidades Address associadas. O código a seguir incorre apenas em um trip de cliente/servidor.
em.getFetchPlan().setMaxFetchDepth(FetchPlan.DEPTH_INFINITE);
tran.begin();
Department dept = (Department) em.find(Department.class, "dept1");
// do something with Address object.
for (Employee e: dept.employees) {
for (Address addr: e.addresses) {
// do something with addresses.
}
}
tran.commit();
Em um ambiente de cliente/servidor, se um plano de carregamento com profundidade zero for utilizado, apenas a entidade raiz será recuperada no primeiro trip de cliente/servidor. Todos os relacionamentos eager são tratados como se fossem lazy.
Exemplo: Neste exemplo, o aplicativo só está interessado no atributo da entidade Department. Ele não precisa acessar seus employees, portanto, o aplicativo configura a profundidade do plano de carregamento como 0.
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");
// do something with dept object.
tran.commit();
Um plano de carregamento de espessura k- tem sua espessura máxima de carregamento configurada para k.
Em um ambiente eXtreme Scale de cliente/servidor, se um plano de carregamento de profundidade k- for utilizado, todos os relacionamentos navegáveis como eager a partir da entidade raiz dentro de k etapas serão recuperados no primeiro trip de cliente/servidor.
O plano de carregamento de profundidade infinita (k = infinito) e o plano de carregamento de profundidade zero (k = 0) são apenas dois exemplos do plano de carregamento de profundidade k-.
Para continuar expandindo o exemplo anterior, suponha que exista outro relacionamento eager da entidade Employee com a entidade Address. Se o plano de carregamento tiver profundidade de busca máxima configurada como 1, a operação em.find(Department.class, "dept1") irá recuperar a entidade Department e todas as entidades Employee em um trip de cliente/servidor. Entretanto, as entidades Address não serão recuperadas porque não são navegáveis como eager para a entidade Department dentro de 1 etapa, mas sim de 2 etapas.
Se você utilizar um plano de carregamento com profundidade configurada como 2, a operação em.find(Department.class, "dept1") irá recuperar a entidade Department, todas as suas entidades Employee e todas as entidades Address associadas às entidades Employee em um trip de cliente/servidor.
Se você executar uma consulta de entidade, também será possível utilizar um plano de carregamento para customizar a recuperação de relacionamento.
Por exemplo, o resultado da consulta SELECT d FROM Department d WHERE "d.deptName='Department'" tem um relacionamento com a entidade Department. Observe que a profundidade do plano de carregamento começa com a associação do resultado da consulta: nesse caso, a entidade Department, não o resultado da consulta em si. Ou seja, a entidade Department está no nível de profundidade de busca 0. Entretanto, um plano de carregamento com profundidade de busca máxima de 1 irá recuperar a entidade Department e suas entidades Employee em um trip de cliente/servidor.
Exemplo: Neste exemplo, a profundidade do plano de carregamento está configurada como 1, portanto, a entidade Department e suas entidades Employee são recuperadas em um trip de cliente/servidor, mas as entidades Address não serão recuperadas no mesmo trip.
Por padrão, todos os relacionamentos navegáveis como eager a partir da entidade raiz serão recuperados em um trip de cliente/servidor. Isso pode melhorar o desempenho se todos os relacionamentos forem utilizados. No entanto, em certos cenários de uso, nem todos os relacionamentos navegáveis como eager a partir da entidade raiz são utilizados, portanto eles incorrem em gasto adicional de tempo de execução e em gasto adicional de largura de banda ao recuperar essas entidades não utilizadas.
Para esses casos, o aplicativo pode configurar a profundidade de busca máxima para um número pequeno para diminuir a profundidade de entidades a serem recuperadas, tornando lazy todas as relações eager após essa profundidade específica. Essa configuração pode melhorar o desempenho.
Continuando com o exemplo Department-Employee-Address anterior, por padrão, todas as entidades Address associadas a employees de Department "dept1" serão recuperadas quando em.find(Department.class, "dept1") for chamado. Se o aplicativo não utilizar entidades Address, ele poderá configurar a profundidade máxima da busca como 1, portanto as entidades Address não serão recuperadas com a entidade Department.