[RESOLVIDO] Enums no Hibernate

Bom dia a todos,

Criei um tipo enum em meu sistema e configurei para ser persistido pelo hibernate. Configurei este enum para ser persistido como números (EnumType.ORDINAL), porém percebi que quando altero a ordem dos atributos do enum, o bd não realiza atualização. Então resolvi por mudar o tipo de persistência para strings (EnumType.STRING) para tentar evitar este problema, daí o hibernate parou de salvar os dados porque a coluna do enum é do tipo numérico e o valor passado é do tipo varchar. Se alguém puder me dar uma luz de como fazer para ou alterar a coluna da tabela (Integer para varchar) ou como proceder para que o sistema não se perca toda vez que alguém acidentalmente alterar alguma ordem dos atributos do enum, eu agradeço.

O meu persistence.xml


<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
	<!--Nome do contexto que configura o Provedor de Persistencia -->
	<persistence-unit name="projeto2">
		<provider>org.hibernate.ejb.HibernatePersistence</provider>
		<properties>
			<!--String Conexao com o banco de dados -->
			<property name="hibernate.connection.url" value ="jdbc:mysql://localhost:3306/projeto2"/>
			<!--Dialeto entendido pelo banco -->
			<property name="hibernate.dialect"  value = "org.hibernate.dialect.MySQL5InnoDBDialect"/>
			<!--Driver JDBC para acesso ao banco -->
			<property name="hibernate.connection.driver_class" value = "com.mysql.jdbc.Driver"/>
			<property name="hibernate.connection.username" value="juba"/>
			<property name="hibernate.connection.password" value ="270787"/>
			<!--Metodo de atualizacao -->
			<property name="hibernate.hbm2ddl.auto" value = "update"/>
			<property name="hibernate.show_sql"  value = "true"/>
		</properties>
	</persistence-unit>
</persistence>

A forma pela qual registro a coluna do enum

	@Column(name = "tipoAmbiente")
	@Enumerated(EnumType.ORDINAL)
	private TipoContexto tipoContexto;

E por fim o meu enum


public enum TipoContexto {
	WEB("Web"), DESKTOP("Desktop");
	
	private String nome;
	
	private TipoContexto(String nome){
		this.nome = nome;
	}

	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}
	
	
}

E aqui vai o erro que está dando:


22144 [AWT-EventQueue-0] WARN  org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL Error: 1366, SQLState: HY000
22144 [AWT-EventQueue-0] ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - Incorrect integer value: 'DESKTOP' for column 'tipoAmbiente' at row 1
javax.persistence.RollbackException: Error while committing the transaction
	at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:92)
	at dao.ClasseModelDAO.add(ClasseModelDAO.java:80)
	at dao.ComponenteDAO.salvar(ComponenteDAO.java:13)
	at control.CrtComponente.salvar(CrtComponente.java:165)
	at control.CrtComponente.actionPerformed(CrtComponente.java:36)
	at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at java.awt.AWTEventMulticaster.mouseReleased(Unknown Source)
	at java.awt.Component.processMouseEvent(Unknown Source)
	at javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.awt.Component.processEvent(Unknown Source)
	at java.awt.Container.processEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.run(Unknown Source)
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Incorrect integer value: 'DESKTOP' for column 'tipoAmbiente' at row 1
	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1377)
	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1300)
	at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:80)
	... 30 more
Caused by: org.hibernate.exception.GenericJDBCException: Incorrect integer value: 'DESKTOP' for column 'tipoAmbiente' at row 1
	at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:54)
	at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125)
	at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110)
	at org.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:129)
	at org.hibernate.engine.jdbc.internal.proxy.AbstractProxyHandler.invoke(AbstractProxyHandler.java:81)
	at $Proxy17.executeUpdate(Unknown Source)
	at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:56)
	at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3016)
	at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2918)
	at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3247)
	at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:140)
	at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:362)
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:354)
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:276)
	at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:326)
	at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
	at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1214)
	at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:403)
	at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
	at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
	at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:75)
	... 30 more
Caused by: java.sql.SQLException: Incorrect integer value: 'DESKTOP' for column 'tipoAmbiente' at row 1
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073)
	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4096)
	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4028)
	at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2490)
	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2651)
	at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2683)
	at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2144)
	at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2444)
	at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2362)
	at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2347)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:122)
	... 47 more

Inté…

Você tem que mudar seu banco de dados também, uma coluna do tipo inteiro não vai conseguir guardar um valor em String.

Essas duas páginas podem te ajudar, me esclareceram bastante a respeito do assunto:

http://www.portalarquiteto.com.br/trabalhando-com-jpa-e-enumeracoes/
http://www.vineetmanohar.com/2010/01/3-ways-to-serialize-java-enums/

Espero que de certo. :smiley:

Pera, você mudou a ordem do enum e achou que o hibernate faria o trabalho de mudar o valor no banco?? O.o

Você precisa entender sobre a ferramenta cara, ou então tu lasca teu banco de dados.

Se você muda de ordinal para string, o seu banco também precisa mudar. Mas ao mudar, isso não vai ocorrer automaticamente.

Esse post aqui pode te esclarecer mais sobre isso: Mapeando Datas (Date) e Enum.

Você pode mapear um valor do Enum para o banco, caso não queira usar o ORDINAL ou STRING, mas não é algo trivial.

apesar de ser simples é trabalhoso, você precisa definir um UserType para cada Enum que quer mapear dessa maneira.

Segue link: http://www.gabiaxel.com/2011/01/better-enum-mapping-with-hibernate.html

E sim, isso é específico do Hibernate, se usar outro provider, não sei qual seria a solução.

Boa tarde

Só queria agradecer aos amigos que me ajudaram. Utilizei a forma que o FPaschoal passou nos links, era a forma mais simples e que resolvia o problema, nem precisei fazer muitas alterações. O código ficou assim:


package dao;

public enum TipoContexto {
	
	//Importante 
	//--------------------------------------------------
	//--     NÃO ALTERAR O CÓDIGO DO CONTEXTO     --
	//--------------------------------------------------
	
	WEB("Web", 0), DESKTOP("Desktop", 1);
	
	private String nome;
	private int codigo;
	
	private TipoContexto(String nome, int codigo){
		this.nome = nome;
		this.codigo = codigo;
	}

	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}

	public int getCodigo() {
		return codigo;
	}

	public void setCodigo(int codigo) {
		this.codigo = codigo;
	}
	
	public static TipoContexto getTipoContexto(int codigo){
		for(TipoContexto tc : values()){
			if(tc.codigo == codigo){
				return tc;
			}
		}
		throw new IllegalArgumentException("O tipo de contexto é inválido");
	}
	
	
}

E no mapeamento ficou assim:


	@Column(name = "tipoAmbiente")
	private int tipoContexto;

	public TipoContexto getTipoContexto() {
		return TipoContexto.getTipoContexto(tipoContexto);
	}

	public void setTipoContexto(TipoContexto tipoContexto) {
		this.tipoContexto = tipoContexto.getCodigo();
	}

Com esta mudança a ordem dos enums no código ficou independente do que está no banco de dados. A minha preocupação não era alterar o tipo de dados que estava sendo enviado para o banco, mas evitar que a ordem dos elementos digitados no código afetassem a aplicação.

Mais uma vez obrigado a todos.

Inté…