Erro de mapeamento para chave estrangeira

Olá pessoal,

Sou iniciante em JPA e estou precisando de uma ajuda para configurar o mapeamento que está levantando esta exceção: org.hibernate.AnnotationException: A Foreign key refering br.com.majorEnterpriseJourney.model.Cidade from br.com.majorEnterpriseJourney.model.Acomodacao has the wrong number of column. should be 2

As 3 classes (Acomodação, Cidade e Estado) estão relacionadas da seguinte maneira:

Acomodação está em uma cidade e em um estado.
Uma cidade pode haver muitas acomodações.
Um estado pode haver muitas acomodações.
E o clássico relacionamento entre cidade e estado:
Uma cidade está localizada em um único estado e um estado possui diversas cidades.

O modelo no banco está da seguinte forma:

create table ESTADO (
	ID_ESTADO INTEGER NOT NULL,
	DESCRICAO VARCHAR(100) NOT NULL,
);
alter table ESTADO add constraint PK_ESTADO primary key(ID_ESTADO);

create table CIDADE (
	ID_CIDADE INTEGER NOT NULL,
	DESCRICAO VARCHAR(100) NOT NULL,
	ID_ESTADO INTEGER NOT NULL
);
alter table CIDADE add constraint PK_CIDADE primary key(ID_CIDADE);
alter table CIDADE add constraint FK_ESTADO_CIDADE foreign key(ID_ESTADO) references ESTADO(ID_ESTADO);

create table ACOMODACAO (
	ID_ACOMODACAO INTEGER NOT NULL,
	ID_CIDADE INTEGER NOT NULL,
	ID_ESTADO INTEGER NOT NULL	
);
alter table ACOMODACAO add constraint PK_ACOMODACAO primary key(ID_ACOMODACAO);
alter table ACOMODACAO add constraint FK_CIDADE_ACOMODACAO foreign key(ID_CIDADE) references CIDADE(ID_CIDADE);
alter table ACOMODACAO add constraint FK_ESTADO_ACOMODACAO foreign key(ID_ESTADO) references ESTADO(ID_ESTADO);

As classes estão da seguinte forma:


@Entity
@Table(name="ESTADO")
@NamedQuery(name="Estado.findAll", query="SELECT e FROM Estado e")
public class Estado extends GenericModel implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name="ID_ESTADO")
	private Long idEstado;

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

	//bi-directional many-to-one association to Acomodacao
	@OneToMany(mappedBy="estado")
	private List<Acomodacao> acomodacoes;

	public Estado() {
	}

	public Long getIdEstado() {
		return this.idEstado;
	}

	public void setIdEstado(Long idEstado) {
		this.idEstado = idEstado;
	}

	public String getDescricao() {
		return this.descricao;
	}

	public void setDescricao(String descricao) {
		this.descricao = descricao;
	}

	public List<Acomodacao> getAcomodacoes() {
		return this.acomodacoes;
	}

	public void setAcomodacoes(List<Acomodacao> acomodacoes) {
		this.acomodacoes = acomodacoes;
	}

	public Acomodacao addAcomodacao(Acomodacao acomodacao) {
		getAcomodacoes().add(acomodacao);
		acomodacao.setEstado(this);

		return acomodacao;
	}

	public Acomodacao removeAcomodacao(Acomodacao acomodacao) {
		getAcomodacoes().remove(acomodacao);
		acomodacao.setEstado(null);

		return acomodacao;
	}
}


@Entity
@Table(name="CIDADE")
@NamedQuery(name="Cidade.findAll", query="SELECT e FROM Cidade e")
public class Cidade extends GenericModel implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name="ID_CIDADE")
	private Long idCidade;
	
	@Column(name="ID_ESTADO")
	private Long idEstado;

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

	//bi-directional many-to-one association to Acomodacao
	@OneToMany(mappedBy="cidade")
	private List<Acomodacao> acomodacoes;

	public Cidade() {
	}

	public Long getIdCidade() {
		return this.idCidade;
	}

	public void setIdCidade(Long idCidade) {
		this.idCidade = idCidade;
	}

	public String getDescricao() {
		return this.descricao;
	}

	public void setDescricao(String descricao) {
		this.descricao = descricao;
	}

	public List<Acomodacao> getAcomodacoes() {
		return this.acomodacoes;
	}

	public void setAcomodacoes(List<Acomodacao> acomodacoes) {
		this.acomodacoes = acomodacoes;
	}

	public Acomodacao addAcomodacao(Acomodacao acomodacao) {
		getAcomodacoes().add(acomodacao);
		acomodacao.setCidade(this);

		return acomodacao;
	}

	public Acomodacao removeAcomodacao(Acomodacao acomodacao) {
		getAcomodacoes().remove(acomodacao);
		acomodacao.setCidade(null);

		return acomodacao;
	}

	public Long getIdEstado() {
		return idEstado;
	}

	public void setIdEstado(Long idEstado) {
		this.idEstado = idEstado;
	}
}



@Entity
@Table(name="ACOMODACAO")
@NamedQuery(name="Acomodacao.findAll", query="SELECT a FROM Acomodacao a")
public class Acomodacao extends GenericModel implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name="ID_ACOMODACAO")
	private Long idAcomodacao;

	//bi-directional many-to-one association to Cidade
	@ManyToOne(fetch=FetchType.LAZY)
	//@JoinColumn(name="ID_CIDADE", insertable=false, updatable=false)
	//@JoinColumn(name="ID_CIDADE",  referencedColumnName = "ID_CIDADE")
	@JoinColumn(name="ID_CIDADE")
	private Cidade cidade;

	//bi-directional many-to-one association to Estado
	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name="ID_ESTADO")
	private Estado estado;

	public Acomodacao() {
	}

	public Long getIdAcomodacao() {
		return this.idAcomodacao;
	}

	public void setIdAcomodacao(Long idAcomodacao) {
		this.idAcomodacao = idAcomodacao;
	}

	public Cidade getCidade() {
		return this.cidade;
	}

	public void setCidade(Cidade cidade) {
		this.cidade = cidade;
	}

	public Estado getEstado() {
		return this.estado;
	}

	public void setEstado(Estado estado) {
		this.estado = estado;
	}
}

Tentei usar as anotações insertable=false, updatable=false e referencedColumnName no mapeamento @ManyToOne de Acomodação com Cidade mas
não resolveu, permanecendo com o mesmo erro.

Qualquer ajuda será válida.
Agraceço a colaboração.

Não entendi direito. Se você tem uma Acomodacao e esta, obrigatoriamente, se encontra em uma Cidade, por que precisa do Estado, sendo que uma Cidade, obrigatoriamente, se encontra em um Estado.
“Ah, drsmachado, eu posso ter duas cidades com mesmo nome em estados diferentes”. Sim, pode, mas você não vai usar a mesma PK para ambas, certo?
Exemplo: Palmas, capital do Tocantins e Palmas, no Paraná. Você terá duas cidades, ligadas a dois estados distintos, mas com PKs diferentes.
Logo, creio que você só precisa de um atributo cidade em suas acomodações (a não ser que uma acomodação de uma cidade possa estar em um estado diferente daquele em que a cidade está…)

Ok, drsmachado,

Vou corrigir isso, na verdade é um facilitador para o meu modelo, para não precisar fazer um inner join com estado apenas para pegar esta informação eu achei melhor ter o id de estado em acomodação, mas isso pode estar realmente causando uma confusão para o JPA/Hibernate.

Vou alterar isso e verificar o comportamento, volto a entrar em contato caso o problema persista.
Obrigado.

Olá drsmachado,

Removi a coluna de estado em acomodação tanto no modelo quanto na classe porém o erro continuou, então eu alterei a relação em acomodação com cidade de @ManyToOne para @OneToMany e mesmo assim o erro continuou. O erro parou de acontecer quando eu alterei para uma coluna simples em acomodação da seguinte forma:

@Column(name=“ID_CIDADE”)
private Cidade cidade;

Não sei se realmente esta é a forma correta de fazer o relacionamento.
Em cidade eu mantive:

//bi-directional many-to-one association to Acomodacao
@OneToMany(mappedBy=“cidade”)
private List acomodacoes;

De qualquer forma não entendi o erro e não sei por que estava sempre informando que deveriam ser 2 colunas no relacionamento de acomodação com cidade, mesmo depois de remover o estado de acomodação.

Se alguém puder esclarecer estas dúvidas eu ficaria muito grato.

Além disso ainda continuo obtendo este erro:

Caused by: org.hibernate.MappingException: Foreign key (FK56F718A53ABAD36E:ACOMODACAO [ID_CIDADE])) must have same number of columns as the referenced primary key (CIDADE [ID_CIDADE,id])

Descobri o erro, existia um arquivo hibernate.cfg.xml que estava fazendo o mapeamento dos objetos de acordo com as configurações do hibernate quando as classes model estavam com o mapeamento jpa definido, este arquivo eu havia adicionado ao projeto e tinha esquecido de remover. Depois que removi do projeto o jboss passou a não apresentar mais este erro.

Agradecimentos,