3
respostas

FetchType.LAZY é má prática, ou tem como contornar?

Olá a todos!

Para testar e tentar por em prática o que foi aprendido no curso de JPA, apliquei o FetchType.LAZY no relacionamento @ManyToOne entre Funcionários e Cargos:

@Entity
@Table(name = "funcionarios")
public class Funcionario {

// outros atributos

@ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "cargo_id", nullable = false)
    private Cargo cargo;

}

Porém, como era de se esperar, na primeira consulta ao Visualizar dos Funcionários, tomei uma LazyInitializationException, por pedir que o cargo viesse atrelado ao nome do funcionário.

Imagino que, por baixo dos panos, o Spring tenha encerrado o acesso ao banco de dados antes de consultar o cargo do funcionário. É plausível essa hipótese?

Assim sendo, aplicar o FetchType.LAZY ao usar o Spring é má prática?

Ou existe alguma forma equivalente ao JOIN FETCH da JPA para prever as consultas agrupadas?

3 respostas

Para deixar mais claro, o problema surgiu em uma consulta simples pelo nome do funcionário:

@Repository
public interface FuncionarioRepository extends CrudRepository<Funcionario, Integer> {

    List<Funcionario> findByNome(String nome);
}
@Service
public class BuscaService {

//

private void buscarFuncionarioPeloNome(Scanner scanner) {
        System.out.println("Digite o nome a ser pesquisado");
        String nome = scanner.nextLine();
        nome += scanner.nextLine();
        List<Funcionario> funcionariosPorNome = funcionarioRepository.findByNome(nome);
        funcionariosPorNome.forEach(System.out::println);
    }
}

Como o ToString de Funcionário inclui o Cargo, aí deu pau:

@Entity
@Table(name = "funcionarios")
public class Funcionario {

//

@Override
    public String toString() {
        return String.format("%s (%s), %s", this.nome, this.cpf, this.cargo);
    }
}

Eu consegui solucionar com base na aula "04 - Usando JPQL" [ https://cursos.alura.com.br/course/spring-data-jpa/task/83437 ].

Montei uma Query usando o JOIN FETCH e resolveu o problema.

@Repository
public interface FuncionarioRepository extends CrudRepository<Funcionario, Integer> {

    @Query("SELECT f FROM Funcionario f JOIN FETCH f.cargo WHERE f.nome = :nome")
    List<Funcionario> buscarFuncionarioComCargo(String nome);
}
@Service
public class BuscaService {

//

private void buscarFuncionarioComCargoPeloNome(Scanner scanner) {
        System.out.println("Digite o nome a ser pesquisado com cargo");
        String nome = scanner.nextLine();
        nome += scanner.nextLine();
        List<Funcionario> funcionariosPorNomeComCargo = funcionarioRepository.buscarFuncionarioComCargo(nome);
        funcionariosPorNomeComCargo.forEach(System.out::println);
    }
}

Existe alguma outra solução para o FetchType.LAZY, ou o caminho é esse mesmo?

Utilizando JPQL em consultas com Spring Data no repositório, esse método com a notação @Query obtém dados de uma entidade baseado em um campo da outra entridade.

@Repository public interface FuncionarioRepository extends CrudRepository<Funcionario, Integer> { @Query("SELECT f FROM Funcionario f JOIN f.unidadeTrabalhos u WHERE u.descricao = :descricao") List findByUnidadeTrabalhosDescricao(String descricao); }

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software