Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

[Projeto] Erro no item 3 do desafio 2 --> org.hibernate.LazyInitializationException

Spring

@SpringBootApplication
public class Desafio02Application implements CommandLineRunner {

    @Autowired
    private ProdutoRepository produtoRepository;

    @Autowired
    private CategoriaRepository categoriaRepository;

    @Autowired
    private PedidoRepository pedidoRepository;


    public static void main(String[] args) {
        SpringApplication.run(Desafio02Application.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        Principal principal = new Principal(produtoRepository, categoriaRepository, pedidoRepository);
        principal.salvarNoBanco();
    }
}

Principal

@Component
public class Principal {
    @Autowired
    private CategoriaRepository categoriaRepository;

    @Autowired
    private ProdutoRepository produtoRepository;

    private PedidoRepository pedidoRepository;


    public Principal(ProdutoRepository produtoRepository, CategoriaRepository categoriaRepository, PedidoRepository pedidoRepository) {
        this.produtoRepository = produtoRepository;
        this.categoriaRepository = categoriaRepository;
        this.pedidoRepository = pedidoRepository;
    }

    public void salvarNoBanco(){
     
        Categoria categoriaEletronicos = new Categoria(null, "Eletrônicos");
        Categoria categoriaLivros = new Categoria(null, "Livros");


        Produto produto1 = new Produto("Notebook", 3500.0, categoriaEletronicos);
        Produto produto2 = new Produto("Smartphone", 2500.0, categoriaEletronicos);
        Produto produto3 = new Produto("Livro de Java", 100.0, categoriaLivros);
        Produto produto4 = new Produto("Livro de Spring Boot", 150.0, categoriaLivros);

 
        categoriaEletronicos.setProdutos(List.of(produto1, produto2));
        categoriaLivros.setProdutos(List.of(produto3, produto4));

        // Salvando categorias (cascateia produtos automaticamente, se configurado)
        categoriaRepository.saveAll(List.of(categoriaEletronicos, categoriaLivros));

        // Testando a persistência e o relacionamento
        System.out.println("Categorias e seus produtos:");
        categoriaRepository.findAll().forEach(categoria -> {
            System.out.println("Categoria: " + categoria.getNome());
            categoria.getProdutos().forEach(produto ->
                    System.out.println(" - Produto: " + produto.getNome())
            );
        });

    }
}

application.properties

spring.application.name=Desafio02

spring.datasource.url=jdbc:postgresql://${DB_HOST}/gerenciador-pedidos
spring.datasource.username=${DB_USER}
spring.datasource.password=${DB_PASSWORD}
spring.datasource.driver-class-name=org.postgresql.Driver
hibernate.dialect=org.hibernate.dialect.HSQLDialect

spring.jpa.hibernate.ddl-auto=update

Categoria

@Entity
public class Categoria {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // Gera automaticamente
    private Long id;
    private String nome;

    @OneToMany(mappedBy = "categoria", cascade = CascadeType.ALL)
    List<Produto> produtos;

    public Categoria(Long id, String nome) {
        this.id = id;
        this.nome = nome;
    }

    public Categoria() {
    }

    public Long getId() {
        return id;
    }

    public String getNome() {
        return nome;
    }

    public List<Produto> getProdutos() {
        return produtos;
    }

    public void setProdutos(List<Produto> produtos) {
        this.produtos = produtos;
    }
}

Produto

@Entity
public class Produto {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)

    private Long id;

    @Column(nullable = false, unique=true)
    private String nome;

    @Column(name = "valor")
    private Double preco;

    @ManyToOne
    // Nome da chave fk --> categoria_id
    @JoinColumn(name = "categoria_id")
    private Categoria categoria;

    public Produto(String nome, Double preco, Categoria categoria) {
        this.nome = nome;
        this.preco = preco;
        this.categoria = categoria;
    }

    public Produto() {
    }

    public Long getId() {
        return id;
    }

    public String getNome() {
        return nome;
    }

    public Double getPreco() {
        return preco;
    }

    public Categoria getCategoria() {
        return categoria;
    }

    public void setCategoria(Categoria categoria) {
        this.categoria = categoria;
    }
}

Pedido

@Entity
public class Pedido {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // Gera automaticamente
    private Long id;
    private LocalDate data;
    
    public Pedido(Long id, LocalDate data) {
        this.id = id;
        this.data = data;
    }

    public Pedido() {
    }

    public Long getId() {
        return id;
    }

    public LocalDate getData() {
        return data;
    }
}
2 respostas

Os imports e os repositórios foram omitidos para respeitar o limite de caracteres.

solução!

Olá Kaio! Tudo bem?

O erro org.hibernate.LazyInitializationException que você está enfrentando geralmente ocorre quando você tenta acessar uma coleção ou propriedade que está configurada para carregamento "lazy" fora do contexto de uma sessão do Hibernate. Isso acontece porque o Hibernate não mantém a sessão aberta após a execução do método que carrega os dados.

Para resolver esse problema, você pode considerar algumas abordagens:

  1. Eager Fetching: Mude o carregamento da coleção de produtos para "eager" ao invés de "lazy". Isso pode ser feito alterando a anotação @OneToMany na sua classe Categoria para incluir fetch = FetchType.EAGER. No entanto, tenha cuidado com essa abordagem, pois ela pode impactar a performance se você tiver muitas entidades relacionadas.

    @OneToMany(mappedBy = "categoria", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    List<Produto> produtos;
    
  2. Open Session in View: Outra abordagem é usar o padrão "Open Session in View", que mantém a sessão aberta durante a execução da requisição HTTP. Isso é mais comum em aplicações web, mas pode ser configurado em aplicações Spring Boot.

  3. Explicit Fetching: Você pode também explicitamente carregar a coleção antes de sair do contexto da transação. Isso pode ser feito usando consultas específicas no repositório para buscar a coleção que você precisa.

  4. Transactional: Certifique-se de que o método salvarNoBanco() está sendo executado dentro de uma transação. Você pode fazer isso anotando o método com @Transactional.

    @Transactional
    public void salvarNoBanco() {
        // seu código
    }
    

Se você optar por usar o @Transactional, certifique-se de que a classe Principal está sendo gerenciada pelo Spring como um componente, o que já parece ser o caso no seu código.

Espero ter ajudado e bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.