Erro ao referenciar foreign key no hibernate

Ola, boa tarde.
Estou com o seguinte erro no código:

org.hibernate.MappingException: Foreign key (FKf16do0lc0mqb2pjqvsjoj1ujr:tb_sega_vip_secretaria [secretarias_id_secretaria,secretarias_id_vip])) must have same number of columns as the referenced primary key (tb_sega_vip_secretaria [id,secretarias_id_secretaria,secretarias_id_vip])

E minhas classes Model são:

Usuário:

import javax.persistence.CascadeType;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

import org.springframework.context.annotation.Scope;
import org.springframework.web.context.WebApplicationContext;

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

@Entity
@Table(name = "portal_sega_user")
@Scope(value=WebApplicationContext.SCOPE_SESSION)
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "usuario")
public class Usuario {

	public Usuario() {

	}

	public Usuario(String usuario, boolean inativo, String nome, String telefoneFixo, String telefoneCelular,
			String cargo, String email, String centroDeCusto, String localidade, String site, String endCompleto,
			String observacao,Set<Perfil> perfis, Set<Secretaria> secretarias) {
		super();
		this.usuario = usuario;
		this.inativo = inativo;
		this.nome = nome;
		this.telefoneFixo = telefoneFixo;
		this.telefoneCelular = telefoneCelular;
		this.cargo = cargo;
		this.email = email;
		this.centroDeCusto = centroDeCusto;
		this.localidade = localidade;
		this.site = site;
		this.endCompleto = endCompleto;
		this.observacao = observacao;
		this.perfis = perfis;
		this.secretarias = secretarias;
	}

	@Id
	private String usuario;
	private boolean inativo;
	private boolean secundariaAtivo;
	private String nome;
	private String telefoneFixo;
	private String telefoneFixoOpc;
	private String telefoneCelular;
	private String telefoneCelularOpc;
	private String cargo;
	private String email;
	private String centroDeCusto;
	private String localidade;
	private String site;
	private String endCompleto;
	private String observacao;

	@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.DETACH)
	@JoinTable(name = "portal_sega_perfil", joinColumns = { @JoinColumn(name = "usuario_id") }, inverseJoinColumns = {
			@JoinColumn(name = "perfis_id") })
	private Set<Perfil> perfis = new HashSet<>(); // perfis

	@ManyToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
	@JoinTable(name="tb_sega_vip_secretaria",joinColumns = {@JoinColumn(name="id")})
	private Set<Secretaria> secretarias = new HashSet<Secretaria>();


	public String getUsuario() {
		return usuario;
	}

	public void setUsuario(String usuario) {
		this.usuario = usuario;
	}

	public boolean isInativo() {
		return inativo;
	}


	public void setInativo(boolean ativo) {
		this.inativo = ativo;
	}

	public boolean isSecundariaAtivo() {
		return secundariaAtivo;
	}

	public void setSecundariaAtivo(boolean secundariaAtivo) {
		this.secundariaAtivo = secundariaAtivo;
	}

	public String getNome() {
		return nome;
	}

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

	public Set<Perfil> getPerfis() {
		return perfis;
	}

	public void setPerfis(Set<Perfil> perfis) {
		this.perfis = perfis;
	}

	public String getTelefoneFixo() {
		return telefoneFixo;
	}

	public void setTelefoneFixo(String telefoneFixo) {
		this.telefoneFixo = telefoneFixo;
	}

	public String getTelefoneCelular() {
		return telefoneCelular;
	}

	public void setTelefoneCelular(String telefoneCelular) {
		this.telefoneCelular = telefoneCelular;
	}
	public String getTelefoneFixoOpc() {
		return telefoneFixoOpc;
	}

	public void setTelefoneFixoOpc(String telefoneFixoOpc) {
		this.telefoneFixoOpc = telefoneFixoOpc;
	}

	public String getTelefoneCelularOpc() {
		return telefoneCelularOpc;
	}

	public void setTelefoneCelularOpc(String telefoneCelularOpc) {
		this.telefoneCelularOpc = telefoneCelularOpc;
	}

	public String getCargo() {
		return cargo;
	}

	public void setCargo(String cargo) {
		this.cargo = cargo;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getCentroDeCusto() {
		return centroDeCusto;
	}

	public void setCentroDeCusto(String centroDeCusto) {
		this.centroDeCusto = centroDeCusto;
	}

	public String getLocalidade() {
		return localidade;
	}

	public void setLocalidade(String localidade) {
		this.localidade = localidade;
	}

	public String getSite() {
		return site;
	}

	public void setSite(String site) {
		this.site = site;
	}

	public String getEndCompleto() {
		return endCompleto;
	}

	public void setEndCompleto(String endCompleto) {
		this.endCompleto = endCompleto;
	}

	public String getObservacao() {
		return observacao;
	}

	public void setObservacao(String observacao) {
		this.observacao = observacao;
	}

	public Set<Secretaria> getSecretarias() {
		return secretarias;
	}

	public void setSecretarias(Set<Secretaria> secretarias) {
		this.secretarias = secretarias;
	}
}

e

Secretaria:

import javax.persistence.CascadeType;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

@Entity
@Table(name = "tb_sega_vip_secretaria")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class)
public class Secretaria {

	/*
	 * chave composta da tabela tb_sega_vip_secretaria
	 */
	@EmbeddedId
	private SecretariaId id;

	/*
	 * tipo de secretaria
	 * 1 = primaria
	 * 2 = secundaria
	 */
	private boolean tipo;

	@ManyToMany(mappedBy = "secretarias",cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	@JsonIgnore
	private Set<Usuario> users = new HashSet<>();

	public Set<Usuario> getUsers() {
		return users;
	}
	public void setUsers(Set<Usuario> users) {
		this.users = users;
	}

	public boolean isTipo() {
		return tipo;
	}
	public void setTipo(boolean tipo) {
		this.tipo = tipo;
	}
}

Secretaria Id ( por se tratar de uma chave composta )

import javax.persistence.Embeddable;

@Embeddable
public class SecretariaId implements Serializable {

	private String id_vip;
	private String id_secretaria;

	public SecretariaId() {};

	/**
	 * @param id_vip
	 * @param id_secretaria
	 */
	public SecretariaId(String id_vip, String id_secretaria) {
		super();
		this.id_vip = id_vip;
		this.id_secretaria = id_secretaria;
	}

	public String getId_vip() {
		return id_vip;
	}

	public void setId_vip(String id_vip) {
		this.id_vip = id_vip;
	}

	public String getId_secretaria() {
		return id_secretaria;
	}

	public void setId_secretaria(String id_secretaria) {
		this.id_secretaria = id_secretaria;
	}
}

Alguem ja passou por este problema?

Grato!

Obs: Modelo do banco:

Portal Sega User

-- Create table
create table PORTAL_SEGA_USER
(
  USUARIO            VARCHAR2(100) not null,
  ATIVO              CHAR(1) default '1',
  NOME               VARCHAR2(100),
  INATIVO            CHAR(1),
  TELEFONEFIXO       VARCHAR2(20),
  TELEFONECELULAR    VARCHAR2(20),
  CARGO              VARCHAR2(40),
  EMAIL              VARCHAR2(50),
  CENTRODECUSTO      VARCHAR2(15),
  LOCALIDADE         VARCHAR2(20),
  SITE               VARCHAR2(40),
  ENDCOMPLETO        VARCHAR2(50),
  OBSERVACAO         VARCHAR2(200),
  TELEFONEFIXOOPC    VARCHAR2(20),
  TELEFONECELULAROPC VARCHAR2(20)
)
tablespace URA_DATA
  pctfree 10
  initrans 1
  maxtrans 255
  storage
  (
	initial 64K
	next 1M
	minextents 1
	maxextents unlimited
  );
-- Create/Recreate primary, unique and foreign key constraints 
alter table PORTAL_SEGA_USER
  add primary key (USUARIO)
  using index 
  tablespace URA_DATA
  pctfree 10
  initrans 2
  maxtrans 255
  storage
  (
	initial 64K
	next 1M
	minextents 1
	maxextents unlimited
  );
-- Create/Recreate check constraints 
alter table PORTAL_SEGA_USER
  add check ("ATIVO"=0 OR "ATIVO"=1);

tb sega vip secretaria:

create table TB_SEGA_VIP_SECRETARIA
(
  ID_VIP        VARCHAR2(100) not null,
  ID_SECRETARIA VARCHAR2(100) not null,
  TIPO          NUMBER(1)
)
tablespace URA_DATA
  pctfree 10
  initrans 1
  maxtrans 255
  storage
  (
	initial 64K
	next 1M
	minextents 1
	maxextents unlimited
  );
-- Create/Recreate primary, unique and foreign key constraints 
alter table TB_SEGA_VIP_SECRETARIA
  add primary key (ID_VIP, ID_SECRETARIA)
  using index 
  tablespace URA_DATA
  pctfree 10
  initrans 2
  maxtrans 255
  storage
  (
	initial 64K
	next 1M
	minextents 1
	maxextents unlimited
  );

Como a chave da tabela tb_sega_vip_secretaria é composta, então seu @JoinTable deve levar em consideração essas colunas chave:

@JoinTable(name = "TB_SEGA_VIP_SECRETARIA", joinColumns = {
	@JoinColumn(name = "ID_VIP"),
	@JoinColumn(name = "ID_SECRETARIA")
})
1 curtida

Opa Lucas, obrigado pelo retorno.
Quando coloco nesse formato, ele mostra que há numero errado de colunas referenciadas.

A Foreign key refering br.com.claro.tcc.web.portalsega.model.Usuario from br.com.claro.tcc.web.portalsega.model.Secretaria has the wrong number of column. should be 1

Hmmm, acho que para facilitar, vc podia mandar o modelo envolvendo essas tabelas (portal_sega_user, tb_sega_vip_secretaria) pra gente entender melhor.

Editei a pergunta com os modelos pra facilitar.

1 curtida

Esse ID_VIP se refere à PORTAL_SEGA_USER?

Ele é uma das chaves primarias da tb_sega_vip_secretaria

Hmmm, essa relação tah parecendo ser mais um one-to-many do que many-to-many.

Isso é uma coisa que ja deu uma discussão cabulosa sobre o tipo de relação haha ai chegamos a conclusão que seria many to many.

Pq a relação é tipo

1 usuário pode ser secretaria ou vip
1 vip pode ter 1 ou mais secretarias
1 secretaria pode ter 1 ou mais vips

enfim, achamos que fazer o many to many seria a melhor forma.

1 curtida

Entendi. Então a tabela TB_SEGA_VIP_SECRETARIA acaba que é uma associativa entre o usuário e outro usuário que é uma secretaria. Se for isso mesmo o ID_VIP representa um usuário e ID_SECRETARIA também representa um usuário. E não há uma tabela que representa a secretária propriamente dita.

É isso mesmo?

Exato. Isso mesmo.

Existe uma tabela que mostra o perfil do usuário, onde eu posso consultar o tipo dele, se é vip ou Secretaria. mas o entendimento nesta tabela é isso mesmo.

Faça um teste dessa forma:

@JoinTable(name = "TB_SEGA_VIP_SECRETARIA",
	joinColumns = @JoinColumn(name = "ID_VIP", referencedColumnName = "USUARIO"),
	inverseJoinColumns = @JoinColumn(name = "ID_SECRETARIA", referencedColumnName = "USUARIO")
)

Suponde que USUARIO seja o ID da tabela PORTAL_SEGA_USER

1 curtida

Sim o Usuario é o “Id” da tabela Users mesmo.

O retorno foi esse

org.hibernate.MappingException: Unable to find column with logical name: id_vip in org.hibernate.mapping.Table(portal_sega_user) and its related supertables and secondary tables