Dado errado memória x banco [RESOLVIDO]

Resolvido: Era um erro ridículo meu. O setter tava fazendo “saldo = valor” sem nenhuma verificação. Vergonhoso, mas a gente não pode só contar vitória… :oops:

Galera, eu tô com o seguinte problema:
Eu tenho um método do DAO que traz somente objetos com saldo >= 0.
Esse método traz os objetos corretos (com saldo >= no banco). Porém, ao verificar o saldo deles no debug, estão com o saldo original de quando foram cadastrados (saldo = valor original).

Ou seja, no banco o saldo é correto, mas ao trazer pra memória eles ficam incorretos.

Alguém sabe me dizer porquê?

[quote=fasts]Galera, eu tô com o seguinte problema:
Eu tenho um método do DAO que traz somente objetos com saldo >= 0.
Esse método traz os objetos corretos (com saldo >= no banco). Porém, ao verificar o saldo deles no debug, estão com o saldo original de quando foram cadastrados (saldo = valor original).

Ou seja, no banco o saldo é correto, mas ao trazer pra memória eles ficam incorretos.

Alguém sabe me dizer porquê?[/quote]

Estamos envolvendo EJB nesse processo ? Transações ? Ou é um simples JDBC ?
Tente imprimir apenas o saldo dos objetos, sem usar o debug. Pode ter “lixo” no seu debug. Assim, terás certeza do retorno e por via das dúvidas, confira sua query e qualquer dúvida, poste o código.

É um simples JDBC mesmo.
Eu fiz o que tu falou: inseri um objeto que altera os saldos.

Antes eram (no banco e na memória):
762.659,97
312.774,16

Agora, no banco:
0,00
75.434,13

Agora, na memória:
(o primeiro objeto nem é trazido pelo método do dao, pois não possui mais saldo positivo).
312.774,16 (mesmo saldo da primeira vez).

Código colega, código. Sem ele vai ser difícil auxiliarmos em algo. Não esqueça de utilizar as tags code, inclusive, poste a Query (caso ela não esteja visível em seu código).

Abraços.

Método que lista os objetos:

@SuppressWarnings("unchecked")
	public List<Empenho> listarComSaldoPositPorObra(String nomeObra) {
		Session sessao = pegarSessao();
		sessao.flush();
		try {
			Criteria criteria = sessao.createCriteria(Empenho.class)
					.addOrder(Order.asc("data")).add(Restrictions.gt("saldo", BigDecimal.ZERO))
					.createCriteria("obra").add(Restrictions.eq("nome", nomeObra));
			return criteria.list();
		} finally {
			sessao.close();
		}
	}

Métodos do DAO usados na situação:

protected Session pegarSessao() {
        Session sessao = HibernateUtil.getSessionFactory().openSession();
        return sessao;
    }

//...

public void salvar(T entidade) {
        if (entidade == null) {
            throw new IllegalArgumentException();
        }
        Session sessao = pegarSessao();
        Transaction transacao = sessao.beginTransaction();
        try {
            sessao.save(entidade);
            transacao.commit();
        } catch (ConstraintViolationException e) {
            transacao.rollback();
            throw e;
        } finally {
        	sessao.flush();
            sessao.close();
        }
    }

//...

public void atualizar(T entidade) {
        if (entidade == null) {
            throw new IllegalArgumentException("Entidade nula!");
        }
        Session sessao = pegarSessao();
        
        Transaction transacao = sessao.beginTransaction();
        try {
            sessao.update(entidade);
            transacao.commit();
        } catch (ConstraintViolationException e) {
            transacao.rollback();
            throw e;
        } catch (NonUniqueObjectException nuoe) { 
        	transacao.rollback();
        	throw nuoe;
        } finally {
            sessao.close();
        }
    }

Desde quando isso é um simples JDBC ?
Tais usando transação (perguntei antes colega), tais abrindo e fechando sessão hibernate (péssima prática), usando criteria e etc.
Não se trata de algo tão trivial.

Quando cadastrar veja se o valor foi atualizado corretamente no banco. Pode estar na mesma transação e o hibernate não encontra o valor atualizado, pois compartilha da mesma transação e os valores ainda não estão persistidos no contexto dele.

Foi mal, não me liguei na pergunta corretamente.

Como falei, os valores são atualizados no banco, e ao puxar uma lista com esses objetos, os mesmos não estão com os saldos atualizados.

PS: Por que isso é uma péssima prática? O que é seria a melhor prática?

nel, obrigado pela contribuição!

Porque é uma péssima prática ?
Deixa eu reformular, peço desculpas .

Será uma péssima prática caso você esteja usando um sistema web, ou seja, rodando seu sistema dentro de um container web ou servidor de aplicação.
Se esse é o caso, sim, é uma péssima prática. De qualquer forma, se for desktop, dá uma pesquisada como o pessoal costuma usar e os pattern para tal, se realmente tu precisa a cada consulta/insert/delete/update ficar abrindo e/ou fechando sessão, pois é a mesma ideia de quando usamos JDBC, onde criamos um pool de conexão.

Se você fizer somente a busca e não estiver retornando o resultado esperado, me parece algo relacionado a sua Criteria. Infelizmente, conheço muito pouco de criteria.
Sabes informar a query que ela está retornando ? E sua entidade, como esta definida ?

Abraços.

Ah, sim… Entendi. Vou ver.
Não há porque pedir desculpas. :wink:

Cara, as queries são as seguintes:

Hibernate: 
    insert 
    into
        NotaFiscal  
        (DATA_EMISSAO, INSS, ISS, MEDICAO, NUMERO, obra_id, PROCESSO_DE_FATURA, VALOR, notafiscal_id)  
    values
        (?, ?, ?, ?, ?, ?, ?, ?, ?)

Hibernate: 
    insert 
    into
        EmpenhoNotaFiscal  //nota fiscal tem uma ligação * to * com empenho
        (valor, empenho_id, notafiscal_id) 
    values
        (?, ?, ?)

Hibernate: 
    insert 
    into
        EmpenhoNotaFiscal
        (valor, empenho_id, notafiscal_id) 
    values
        (?, ?, ?)

Hibernate: 
    select
        empenhonot_.empenho_id,
        empenhonot_.notafiscal_id,
        empenhonot_.valor as valor13_ 
    from
        EmpenhoNotaFiscal empenhonot_ 
    where
        empenhonot_.empenho_id=? 
        and empenhonot_.notafiscal_id=?

Hibernate: 
    update
        Empenho 
    set
        DATA=?,
        FONTE=?,
        NUMERO=?,
        obra_id=?,
        saldo=?,
        valor=?,
        valorCancelado=? 
    where
        empenho_id=?

Hibernate: 
    select
        empenhonot_.empenho_id,
        empenhonot_.notafiscal_id,
        empenhonot_.valor as valor13_ 
    from
        EmpenhoNotaFiscal empenhonot_ 
    where
        empenhonot_.empenho_id=? 
        and empenhonot_.notafiscal_id=?

Hibernate: 
    update
        Empenho 
    set
        DATA=?,
        FONTE=?,
        NUMERO=?,
        obra_id=?,
        saldo=?,
        valor=?,
        valorCancelado=? 
    where
        empenho_id=?

Se referem a esse trecho do código:

dao.salvar(entidade);
DAOEmpenho daoEmpenho = new DAOEmpenho();
if (empenhos != null)
    for (Empenho e : empenhos)
	daoEmpenho.atualizar(e);

O mapeamento das entidades:

@Entity
public class Empenho implements Comparable<Empenho> {
    //...
    private List<EmpenhoNotaFiscal> ligacoes;
    //...
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "chave.empenho", cascade = CascadeType.ALL)
    public List<EmpenhoNotaFiscal> getLigacoes() {
    	if (ligacoes == null)
    		ligacoes = new ArrayList<>();
		return Collections.unmodifiableList(ligacoes);
    }
}

//###

@Entity
public class NotaFiscal implements Comparable<NotaFiscal> {
    //...
    private List<EmpenhoNotaFiscal> ligacoes;
    //...
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "chave.notaFiscal", cascade = CascadeType.ALL)
    public List<EmpenhoNotaFiscal> getLigacoes() {
    	if (ligacoes == null)
    		ligacoes = new ArrayList<>();
		return Collections.unmodifiableList(ligacoes);
    }
}

//###

@Entity
@AssociationOverrides({
	@AssociationOverride(name = "chave.empenho", joinColumns = @JoinColumn(name = "empenho_id")),
	@AssociationOverride(name = "chave.notaFiscal", joinColumns = @JoinColumn(name = "notafiscal_id"))})
public class EmpenhoNotaFiscal implements Serializable {

    private static final long serialVersionUID = 1L;
    
    @EmbeddedId
    private EmpenhoNotaFiscalPK chave = new EmpenhoNotaFiscalPK();
    private BigDecimal valor;
    //... getters, setters, equals e hashCode
}

//###

@Embeddable
public class EmpenhoNotaFiscalPK implements Serializable {

    private static final long serialVersionUID = -7577249378978451429L;

    @ManyToOne(cascade = CascadeType.ALL)
    private Empenho empenho;

    @ManyToOne(cascade = CascadeType.ALL)
    private NotaFiscal notaFiscal;
    //...
}

Eu percebi que esse relacionamento era desnecessário pro que eu precisava, então agora essas duas entidades não tem mais nenhum vínculo.
Mas mesmo assim estou com o mesmo problema lá de cima: tenho um valor de saldo no banco de dados e outro valor ao puxar o objeto de lá (o que mostra que o relacionamento não tem nada a ver).

Hum! Cara, isso não tem nada de java básico, é hibernate, transações, sessões, JPA…isso é lá em JEE .
Porque sempre retornas uma lista imutável ? E sobre o erro, tenta usar o EAGER ao invés de LAZY e veja o resultado.

Retorno sempre uma lista imutável pra encapsular o conteúdo da lista, evitando que seja possível fazer isso, por exemplo:

o.getContratos().get(0).setDataContrato(new Date());

Como visto aqui (não achei o link que explica em java, mas serve igualmente): http://blog.caelum.com.br/scala-os-cuidados-com-encapsulamento/;
e aqui (tópico pra favoritar): http://www.guj.com.br/java/104592-heranca#564414

PS: Veja também sobre os setters.


Eu já não tenho mais o relacionamento entre essas classes, logo as classes EmpenhoNotaFiscal e EmpenhoNotaFiscalPK deixaram de existir e não há mais nenhum relacionamento entre Empenho e NotaFiscal.
Portanto, não posso tentar por esse caminho, de mudar o FetchType.

PS: Não postei lá em “Persistência”, porque quase ninguém responde… Pelo menos comigo. Postei lá uma vez e até hoje nenhuma resposta :lol:

Não precisa me explicar sobre encapsulamento e etc, só achei curioso isso.
Cara, está bem estranho, nunca tive esse tipo de problema. Já tive problemas com lazy e etc, mas fazer um find no banco e não trazer atualizado, é bem bizarro.

Sinceramente, não sei. Teria de pegar todo o projeto e ir acompanhando o processo, boa sorte.

Tranquilo, valeu!

Alguém aí já passou por uma situação parecida, ou tem alguma idéia de como solucionar?

Resolvido: Era um erro ridículo meu. O setter tava fazendo “saldo = valor” sem nenhuma verificação. Vergonhoso, mas a gente não pode só contar vitória… :oops:

PS: Interessante foi a forma como descobri. Antes de acordar, sonhei com o programa e resolvi o problema no sonho, dessa forma. Logo em seguida acordei e já peguei o notebook pra corrigir. :lol: