Hibernate com problemas mapeando uma coluna para mais de uma referência

10 respostas
E

Fala, pessoal, beleza?

Estou com um problema aqui (que até acredito saber onde é) e não sei nem como procurar a solução.

O cenário é mais ou menos o seguinte:
Peguei um sistema legado para “traduzir” para Java e não querem alterar a modelagem de dados devido a alguns outros sistemas que utilizam o mesmo banco. E nessa modelagem me deparei com o seguinte:

EntidadeA:

  • idEntA
  • campo1a
  • campo2a

EntidadeB:

  • idEntA
  • codEntB
  • campo1b
  • campo2b

EntidadeC:

  • idEntA
  • codEntC
  • campo1c
  • campo2c

EntBxEntC:

  • idEntA
  • codEntB
  • codEntC
  • dataCadastro

É algo mais ou menos assim. Consegui mapear no Hibernate (utilizando Annotations) para consultas, porém quando preciso apagar um registro ele retorna um erro de java.sql.SQLException: Índice de coluna inválido.

O mapeamento da classe de ligação (EntBxEntC) ficou assim:

@Id
	@ManyToOne(cascade = CascadeType.ALL)
	@JoinColumns({
			@JoinColumn(name = "idEntA", referencedColumnName = "idEntA", insertable = false, updatable = false),
			@JoinColumn(name = "codEntB", referencedColumnName = "codEntB", insertable = false, updatable = false) })
	private EntidadeB entidade;

	@Id
	@ManyToOne(cascade = CascadeType.ALL)
	@JoinColumns(value = {
			@JoinColumn(name = "idEntA", referencedColumnName = "idEntA", insertable = false, updatable = false),
			@JoinColumn(name = "codEntC", referencedColumnName = "codEntC", insertable = false, updatable = false) })
	private EntidadeC particularidade;

	@Column(name = "dataCadastro")
	private Date dataCadastro;

Os atributos insertable e updatable como false eu tive que incluir porque senão eu não conseguiria consultar a base.
Ainda não testei inclusão, mas estou tendo problemas para apagar.

Segue o Stack Trace do erro:

16:54:27,592 DEBUG [AbstractBatcher     ] about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
16:54:27,592 DEBUG [SQL                 ] 
    delete 
    from
        EntBxEntC 
    where
        idEntA=? 
        and codEntB=? 
        and codEntC=?
16:54:27,593 TRACE [BasicBinder         ] binding parameter [1] as [BIGINT] - 58391
16:54:27,593 TRACE [BasicBinder         ] binding parameter [2] as [BIGINT] - 4
16:54:27,593 TRACE [BasicBinder         ] binding parameter [3] as [BIGINT] - 1
16:54:27,594 DEBUG [DefaultListableBeanFactory] Creating instance of bean 'jstlLocalization'
16:54:27,594 TRACE [BasicBinder         ] binding parameter [4] as [BIGINT] - 58391
16:54:27,595 DEBUG [AbstractBatcher     ] about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
16:54:27,597 DEBUG [DefaultListableBeanFactory] Returning cached instance of singleton bean 'VRaptorRequestProvider'
16:54:27,597 DEBUG [DefaultListableBeanFactory] Finished creating instance of bean 'jstlLocalization'
16:54:27,598 DEBUG [DefaultListableBeanFactory] Finished creating instance of bean 'defaultValidator'
16:54:27,598 DEBUG [DefaultListableBeanFactory] Finished creating instance of bean 'servlet3MultipartInterceptor'
16:54:27,599 DEBUG [DefaultListableBeanFactory] Creating instance of bean 'exceptionHandlerInterceptor'
16:54:27,602 DEBUG [JDBCExceptionReporter] could not delete: [br.com.operativa.sisma.model.monitor.EntidadeParticularidade#component[particularidade,entidade]{entidade=br.com.operativa.sisma.model.monitor.Entidade#component[codEntidade,convenio]{convenio=br.com.operativa.sisma.model.monitor.Convenio#58391, codEntidade=1}, particularidade=null}] [delete from EntBxEntC where idEntA=? and codEntB=? and codEntC=?]
java.sql.SQLException: Índice de coluna inválido
	at oracle.jdbc.driver.OraclePreparedStatement.setLongInternal(OraclePreparedStatement.java:4901)
	at oracle.jdbc.driver.OraclePreparedStatement.setLong(OraclePreparedStatement.java:4888)
	at oracle.jdbc.driver.OraclePreparedStatementWrapper.setLong(OraclePreparedStatementWrapper.java:206)
	at org.hibernate.type.descriptor.sql.BigIntTypeDescriptor$1.doBind(BigIntTypeDescriptor.java:52)
	at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:91)
	at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:283)
	at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:278)
	at org.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:130)
	at org.hibernate.type.ComponentType.nullSafeSet(ComponentType.java:317)
	at org.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:130)
	at org.hibernate.type.ComponentType.nullSafeSet(ComponentType.java:317)
	at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2684)
	at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2911)
	at org.hibernate.action.EntityDeleteAction.execute(EntityDeleteAction.java:97)
	at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
	at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)
	at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:189)
	at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
	at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
	at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
	at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
	at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
	at br.com.caelum.vraptor.util.hibernate.HibernateTransactionInterceptor.intercept(HibernateTransactionInterceptor.java:46)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:48)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:83)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.interceptor.ExceptionHandlerInterceptor.intercept(ExceptionHandlerInterceptor.java:71)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:69)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.core.EnhancedRequestExecution.execute(EnhancedRequestExecution.java:23)
	at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:92)
	at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:58)
	at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:89)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:185)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:151)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:405)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:269)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:515)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:300)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:662)

10 Respostas

A

cara,

sua situação é bem parecida com a desse link, da uma olhada ai
http://www.guj.com.br/java/248978-resolvido-duvida-sobre-pk-e-erro-ao-inserir-no-banco-de-dados-usando-pk-gerado-pelo-netbeans

t+

E

alissonvla:
cara,

sua situação é bem parecida com a desse link, da uma olhada ai
http://www.guj.com.br/java/248978-resolvido-duvida-sobre-pk-e-erro-ao-inserir-no-banco-de-dados-usando-pk-gerado-pelo-netbeans

t+

Rapaz, a solução do post não resolveu. Tentei inclusive adaptar com o que sei mas ainda assim não resolveu, ele passou a reclamar da coluna duplicada, como transcrevo abaixo.

org.hibernate.MappingException: Repeated column in mapping for entity: br.com.operativa.sisma.model.monitor.EntidadeParticularidade column: idEntA (should be mapped with insert="false" update="false")
	at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:676)

Como eu disse, parece que o problema vem do fato de ter apenas um campo idEntA na tabela de ligação, pois ambas as tabelas possuem esse mesmo campo (vindos de referência - FK - da EntidadeA) em sua chave primária.

A

a solução ta na exceção… :smiley:

should be mapped with insert=“false” update=“false”

t+

E

Infelizmente não… Os relacionamentos já estão marcados como update = false e insert = false…

A

coloca ai o codigo de como ficou suas classes.

t+

E

Pelo visto terei de colocar as classes aqui mesmo (apesar de achar que pode ser um caso não previsto de uso)…

Entidade.java

@Entity
@Table(name = "TP_ENTIDADES")
public class Entidade implements Comparable<Entidade>, Serializable {

	@EmbeddedId
	private EntidadeId id;

	@Column(name = "DESCRICAO")
	private String descricao;

	@OneToMany(cascade = CascadeType.ALL)
	@JoinColumns({
			@JoinColumn(name = "COD_CONVENIO", referencedColumnName = "COD_CONVENIO", insertable = false, updatable = false),
			@JoinColumn(name = "COD_ENTIDADE", referencedColumnName = "COD_ENTIDADE", insertable = false, updatable = false) })
	private List<EntidadeParticularidade> particularidades;

	@OneToMany(cascade = CascadeType.ALL)
	@JoinColumns({
			@JoinColumn(name = "COD_CONVENIO", referencedColumnName = "COD_CONVENIO", insertable = false, updatable = false),
			@JoinColumn(name = "COD_ENTIDADE", referencedColumnName = "COD_ENTIDADE", insertable = false, updatable = false) })
	private List<MonitEntPar> monitEntPars;
}

EntidadeId.java

@Embeddable
public class EntidadeId implements Serializable {

	@Column(name = "COD_ENTIDADE")
	private Long codEntidade;

	@ManyToOne(cascade = CascadeType.ALL)
	@JoinColumn(name = "COD_CONVENIO", referencedColumnName = "COD_CONVENIO")
	private Convenio convenio;
}

Particularidade.java

@Entity
@Table(name = "PARTICULARIDADES")
public class Particularidade implements Comparable<Particularidade>,
		Serializable {

	@EmbeddedId
	private ParticularidadeId id = new ParticularidadeId();

	@Column(name = "DESCRICAO")
	private String descricao;

	@Column(name = "MSG_EMAIL")
	private String msgEmail;

	@Column(name = "ATIVADO")
	private Boolean ativado;

	@OneToMany(cascade = CascadeType.ALL)
	@JoinColumns(value = {
			@JoinColumn(name = "COD_CONVENIO", referencedColumnName = "COD_CONVENIO", insertable = false, updatable = false),
			@JoinColumn(name = "COD_PARTICULARIDADE", referencedColumnName = "COD_PARTICULARIDADE", insertable = false, updatable = false) })
	private List<EntidadeParticularidade> entidades;

	@OneToMany(cascade = CascadeType.ALL)
	@JoinColumns(value = {
			@JoinColumn(name = "COD_CONVENIO", referencedColumnName = "COD_CONVENIO", insertable = false, updatable = false),
			@JoinColumn(name = "COD_PARTICULARIDADE", referencedColumnName = "COD_PARTICULARIDADE", insertable = false, updatable = false) })
	private List<MonitEntPar> monitEntPars;
}

ParticularidadeId.java

@Embeddable
public class ParticularidadeId implements Serializable {

	@Column(name = "COD_PARTICULARIDADE")
	private Long codParticularidade;

	@ManyToOne(cascade = CascadeType.ALL)
	@JoinColumn(name = "COD_CONVENIO", referencedColumnName = "COD_CONVENIO")
	private Convenio convenio;
}

EntidadeParticularidade.java

@Entity
@Table(name = "ENTIDADES_PARTICULARIDADES")
public class EntidadeParticularidade implements
		Comparable<EntidadeParticularidade>, Serializable {

	@JoinColumns({
			@JoinColumn(name = "COD_CONVENIO", referencedColumnName = "COD_CONVENIO", insertable = false, updatable = false),
			@JoinColumn(name = "COD_ENTIDADE", referencedColumnName = "COD_ENTIDADE", insertable = false, updatable = false) })
	@ManyToOne(cascade = CascadeType.ALL)
	@Id
	private Entidade entidade;
	@JoinColumns(value = {
			@JoinColumn(name = "COD_CONVENIO", referencedColumnName = "COD_CONVENIO", insertable = false, updatable = false),
			@JoinColumn(name = "COD_PARTICULARIDADE", referencedColumnName = "COD_PARTICULARIDADE", insertable = false, updatable = false) })
	@ManyToOne(cascade = CascadeType.ALL)
	@Id
	private Particularidade particularidade;

	@Column(name = "DT_CADASTRO")
	private Date dataCadastro;

	@Column(name = "ativado")
	private Boolean ativado;
}

Então, vamos tentar explicar novamente a situação…
A tabela ENTIDADES_PARTICULARIDADES faz a ligação entre as tabelas PARTICULARIDADES e ENTIDADES e ambas possuem o COD_CONVENIO em sua chave primária (que fazem referência à tabela CONVENIO). E a tabela ENTIDADES_PARTICULARIDADES só possui uma ocorrência desse campo. E até consegui mapear, utilizando o insert e update iguais a false, mas só funcionou para consulta. Fiz as alterações que foram sugeridas no outro tópico que você comentou mas ele começou a reclamar que os atributos deveriam ser mapeados com insert e update iguais a false, como já estavam eu não poderia continuar tentando, por isso voltei ao que estava (que é esta versão que postei acima).

A

tenta fazer desse jeito ai,

@Entity
@Table(name = "TP_ENTIDADES")
public class Entidade implements Comparable<Entidade>, Serializable {

	@EmbeddedId
	private EntidadeId id;

	@Column(name = "DESCRICAO")
	private String descricao;

	@OneToMany(cascade = CascadeType.ALL, mappedBy = "particularidade", fetch = FetchType.LAZY)
	private List<EntidadeParticularidade> particularidades;

	@OneToMany(cascade = CascadeType.ALL)
	@JoinColumns({
			@JoinColumn(name = "COD_CONVENIO", referencedColumnName = "COD_CONVENIO", insertable = false, updatable = false),
			@JoinColumn(name = "COD_ENTIDADE", referencedColumnName = "COD_ENTIDADE", insertable = false, updatable = false) })
	private List<MonitEntPar> monitEntPars;
}

@Embeddable
public class EntidadeId implements Serializable {

	@Column(name = "COD_ENTIDADE")
	private Long codEntidade;

	@ManyToOne(cascade = CascadeType.ALL)
	@JoinColumn(name = "COD_CONVENIO", referencedColumnName = "COD_CONVENIO")
	private Convenio convenio;
}


@Entity
@Table(name = "PARTICULARIDADES")
public class Particularidade implements Comparable<Particularidade>,
		Serializable {

	@EmbeddedId
	private ParticularidadeId id = new ParticularidadeId();

	@Column(name = "DESCRICAO")
	private String descricao;

	@Column(name = "MSG_EMAIL")
	private String msgEmail;

	@Column(name = "ATIVADO")
	private Boolean ativado;
	
	@OneToMany(cascade = CascadeType.ALL, mappedBy = "entidade", fetch = FetchType.LAZY)
	private List<EntidadeParticularidade> entidades;

	@OneToMany(cascade = CascadeType.ALL)
	@JoinColumns(value = {
			@JoinColumn(name = "COD_CONVENIO", referencedColumnName = "COD_CONVENIO", insertable = false, updatable = false),
			@JoinColumn(name = "COD_PARTICULARIDADE", referencedColumnName = "COD_PARTICULARIDADE", insertable = false, updatable = false) })
	private List<MonitEntPar> monitEntPars;
}

@Embeddable
public class ParticularidadeId implements Serializable {

	@Column(name = "COD_PARTICULARIDADE")
	private Long codParticularidade;

	@ManyToOne(cascade = CascadeType.ALL)
	@JoinColumn(name = "COD_CONVENIO", referencedColumnName = "COD_CONVENIO")
	private Convenio convenio;
}


@Entity
@Table(name = "ENTIDADES_PARTICULARIDADES")
public class EntidadeParticularidade implements
		Comparable<EntidadeParticularidade>, Serializable {
	
	@EmbeddedId
    protected EntidadeParticularidadeId entidadeParticularidadeId;

    @ManyToOne(optional = false, fetch = FetchType.LAZY)
	@JoinColumn(name = "CHAVE_ESTRANGEIRA", referencedColumnName = "CHAVE_PRIMARIA", insertable = false, updatable = false)
	private Entidade entidade;	
	
    @ManyToOne(optional = false, fetch = FetchType.LAZY)
	@JoinColumn(name = "CHAVE_ESTRANGEIRA", referencedColumnName = "CHAVE_PRIMARIA", insertable = false, updatable = false)
	private Particularidade particularidade;

	@Column(name = "DT_CADASTRO")
	private Date dataCadastro;

	@Column(name = "ativado")
	private Boolean ativado;
}

@Embeddable
public class EntidadeParticularidadeId implements Serializable {
	private static final long serialVersionUID = 1L;
	
	@Basic(optional = false)
    @Column(name = "NOME_COLUNA")
    private Integer entidadeId;
	
    @Basic(optional = false)
    @Column(name = "NOME_COLUNA")
    private Integer particularidadeId;

    public EntidadeParticularidadeId () {
    }

    public EntidadeParticularidadeId (int entidadeId, intparticularidadeId) {
        this.entidadeId = entidadeId;
        this.particularidadeId = particularidadeId;
    }
}

t+

E

Fala, alissonvla, beleza? Cara, depois de olhar o seu mapeamento e ficar um tempo achando que não iria funcionar (pois você deu a entender que era pra usar apenas uma coluna pra ligar as FKs e repetir o um atributo ID - no modelo as FKs fazem parte da FK na tabela ENTIDADES_PARTICULARIDADES), até que decidi tentar adaptar e ver no que daria…
Então, fiz as modificações no seu exemplo pra atenderem ao modelo. Após a alteração passou a não ocorrer mais esse erro, mas um outro:

org.hibernate.PropertyAccessException: could not get a field value by reflection getter of br.com.empresa.sistema.model.monitor.Entidade.id

Depois de pesquisar um bocado no “Santo Google” descobri que isso pode ser um erro devido ao Fetch Lazy do Hibernate… É como se o “objeto proxy” não estivesse conseguindo encontrar a propriedade. E infelizmente minha máquina de desenvolvimento não tem memória suficiente pra testar no modo Eager pra ver se estava certo. Porém notei que quando buscava uma entidade estava retornando um produto cartesiano.

Enfim, voltei ao estado anterior. Tentei uma abordagem diferente para tentar resolver, tentando remover o elemento das listas onde ele se encontrava e atualizando os objetos pra ver se resolvia meu problema mas o erro de PropertyAccessException voltou a ocorrer.

Estou quase aceitando o que me propuseram de usar uma procedure pra remover o registro, mesmo achando uma solução porca demais.

E muito obrigado pela ajuda…

PS: se alguém souber de outro possível solução, por favor avisem…

E

Só pra dar um feedback…

A dica que o alissonvla deu funcionou, só tive que mudar a forma como estava buscando no banco (o meu método que gerava as Criterias para consulta em tempo de execução, por elagum motivo esta dando erro quando chamo o método list do objeto Criteria (o erro citado anteriormente - PropertyAccessException)… Só tive que mudar a abordagem para buscar o elemento no banco…

E um detalhe interessante: eu não sabia que eu poderia ter mais de um atributo referenciando a mesma coluna (eu sei, já estava fazendo isso, mas não havia me tocado nesse detalhe rsrs)…

Muito obrigado pela ajuda, rapaz.

A

bom que resolveu… :lol:

Criado 27 de setembro de 2011
Ultima resposta 29 de set. de 2011
Respostas 10
Participantes 2