| Autor |
Mensagem |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 14/11/2007 10:02:29
|
Eduardo Bregaida
Moderador
Membro desde: 13/11/2003 14:11:35
Mensagens: 2416
Localização: São Caetano do Sul - SP
Offline
|
Na última semana descobri um problema (pra mim é um bug) no Hibernate3 que me deixou muito confuso por algumas horas.
Eu tenho uma entidade do Hibernate chamada Pessoa, que é usada em vários outros sistemas (afinal, todos os sistemas possuem alguma associação com pessoas).
Tudo estava funcionando perfeitamente, até que surgiu a idéia de implementar versioning for optimistic locking nesta classe (se você não conhece como funciona o versionamento do Hibernate, clique aqui). Foi muito simples, apenas adicionei @Version em um atributo do tipo Date e as instâncias ficaram protegidas de alterações concorrentes.
O problema é que, depois dessa alteração, todos os sistemas começaram apresentar problemas em telas variadas. A solução (depois de quebrar muito a cabeça) foi não usar versionamento para esta entidade. Eu sei que na verdade não foi uma solução, mas resolveu o problema. E nessas horas o difícil é imaginar que um simples @Version gerou tudo isso.
Para tentar exemplificar o problema, criei duas entidades chamadas Customer e Invoice, como seguem:
@Entity
@Table
public class Customer implements Serializable {
@Id
@GeneratedValue
private Long id;
private String name;
@Version
@Column(name="update_date")
private Date updateDate;
//getters and setters
}
@Entity
@Table
public class Invoice implements Serializable {
@Id
@GeneratedValue
private Long id;
private Integer number;
private BigDecimal amount;
//getters and setters
}
Veja que o atributo updateDate da classe Customer está anotada com @Version.
Criei um método com o seguinte código para testar o comportamento do Hibernate com @Version:
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
customer.setId(1L);
Invoice invoice = new Invoice();
invoice.setNumber(1234);
invoice.setAmount(new BigDecimal(4500.19));
invoice.setCustomer(customer);
session.merge(invoice);
transaction.commit();
Considere o customer de código 1 já cadastrado no banco de dados.
Agora tente adivinhar o resultado da execução desse código. Pra mim deveria funcionar, pois o merge() deveria tornar o meu objeto customer persistente, mas infelizmente é lançada a seguinte exceção:
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: example.Customer
O engraçado é que se incluirmos a seguinte linha depois de atribuir o código 1 ao id de customer, funciona:
customer.setUpdateDate(new Date(1, 1, 1, 1, 1, 1));
Veja que eu defini uma data de alteração (que nem faz sentido) ao objeto, e agora funciona perfeitamente, gerando o seguinte SQL:
Hibernate: select customer0_.id as id0_0_, customer0_.name as name0_0_, customer0_.update_date as update3_0_0_ from Customer customer0_ where customer0_.id=?
Hibernate: insert into Invoice (amount, customer_id, number) values (?, ?, ?)
Se comentarmos o @Version do atributo updateDate da classe Customer e também a atribuição da data de alteração de Customer, funcionará corretamente também, pois aí não estaria mais utilizando versionamento.
Se quiser fazer outros testes, baixe do código-fonte do projeto de exemplo clicando aqui.
E pra você, isso é um bug? Será que a especificação do JPA contempla isso?
Assim que tiver tempo, irei traduzir esse post e cadastrar no JIRA do Hibernate.
Abraços,
Fonte: http://www.infoblogs.com.br/view.action?contentId=21705
http://www.javafree.org/news/view.jf?idNew=3682
http://www.hibernate.org/hib_docs/annotations/reference/en/html_single/#entity-mapping-entity-version
|
Blog - Java Anywhere
@bregaida - Twitter
Flickr - Fotos
Cursos de Java?
"Você poderia me dizer, por favor, qual caminho eu devo seguir?"
"Isto depende muito de onde você deseja chegar."
-Lewis Carroll, Alice no País das Maravilhas |
|
|
 |
|
|
|
|
|
|