Estou criando uma classe para controlar estoques em locais diferentes, porem a classe “Estoques” possui uma chave composta que esta na classe “EstoquePK”.
Estou utilizando EclipseLink Com JPA. Tudo esta OK dentro do Eclipse, porem quando executo o programa o Java tenta criar a tabela conforma abaixo. Esta retornando o erro “A coluna ‘ID’ da tabela ‘SB2’ é do tipo inválido para uso como coluna de chaves em um índice.”
Isso ocorre porque na criação da coluna B2_COD na classe EstoquesPK estou referenciando a classe produtos.
A criação esta correta, pois como estamos trabalhando com orientação a objeto não posso criara o campo B2_COD como string ja que neste caso este campo se refere a o produto então eu faço a referencia a classe de produtos.
Se eu usar outro banco de dados como o DERBY ele faz a mesma coisa, porem ele cria um campo do tipo Blob. Realmente se eu fizer como string ele funciona, porem fica uma classe sem relacionamento com a classe de produtos.
Não sei como solucionar…
Eu tenho certeza que não, pois o SQL não aceita, mas quem cria o script é o próprio JPA.
Já criei esta tabela manualmente utilizando outro tipo como Varbinary ou Binary e funciona, mas eu fiz manualmente e isso acredito que não esta correto pois é tarefa do JPA.
Eu também ja criei manualmente a tabela sem colocar chave primaria e funciona
Realmente estou perdido
Eu nunca vi isso que ta tentando fazer, de que exemplo ou documentação veio isso? Mesmo se o SQL Server aceitasse seria loucura uma PK como IMAGE.
Tenta retirar o @ManyToOne de EstoquePK e colocar em Estoque, com updatable = false em @JoinColumn. Deixa na PK só os códigos, nada de ManyToOne ou coisa do tipo.
Essa é uma modelagem simples similar a (pedido X item do pedido) onde o item do pedido pode ter chave composta de cabeçalho do pedido + item do pedido e o cabeçalho do pedido é um objeto de outra classe.
Eu tentei fazer conforme vc orientou, o erro mudou, mas ainda não funciona. Caso exista um outra forma de fazer vou apreciar muita a sugestão. Desde já valeu pela força
Segue o erro e fontes alterados, acredito que esta conforme vc sugeriu
Erro: The mapping [B2_COD] from the embedded ID class [entidades.EstoquePK] is an invalid mapping for this class. an embeddableclassthet is used with embedded ID specification (attrribute [id] from the source [class entidades.Estoques]) can only contain basic mappings. Either remove the non basic mapping os change the embedded ID specification on the source to be embedded.
package entidades;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Embeddable;
@Embeddable
public class EstoquesPK implements Serializable {
private static final long serialVersionUID = -637018809489152388L;
private Produtos B2_COD;
@Column(length = 2)
private String B2_LOCAL;
public Produtos getB2_COD() {
return B2_COD;
}
public void setB2_COD(Produtos b2_COD) {
B2_COD = b2_COD;
}
public String getB2_LOCAL() {
return B2_LOCAL;
}
public void setB2_LOCAL(String b2_LOCAL) {
B2_LOCAL = b2_LOCAL;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((B2_COD == null) ? 0 : B2_COD.hashCode());
result = prime * result + ((B2_LOCAL == null) ? 0 : B2_LOCAL.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
EstoquesPK other = (EstoquesPK) obj;
if (B2_COD == null) {
if (other.B2_COD != null)
return false;
} else if (!B2_COD.equals(other.B2_COD))
return false;
if (B2_LOCAL == null) {
if (other.B2_LOCAL != null)
return false;
} else if (!B2_LOCAL.equals(other.B2_LOCAL))
return false;
return true;
}
}
Segue classe Estoques
package entidades;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name = "SB2")
public class Estoques implements Serializable {
private static final long serialVersionUID = 5999236902534007386L;
@EmbeddedId
@Id
@ManyToOne
@JoinColumn(name = "id", referencedColumnName = "id", updatable = false)
private EstoquesPK id;
private int B2_QATU;
private double B2_CMUNIT;
private double B2_VATU;
private double B2_QFIM;
private double B2_VFIM;
@Column(length = 10)
private String B2_DTFECHA;
@Column(length = 10)
private String B2_DTULTINV;
@Column(length = 10)
private String B2_DTCADASTRO;
@Column(length = 10)
private String B2_ALTERA;
@Column(length = 10)
private String B2_DTINTEG;
public EstoquesPK getId() {
return id;
}
public void setId(EstoquesPK id) {
this.id = id;
}
public int getB2_QATU() {
return B2_QATU;
}
public void setB2_QATU(int b2_QATU) {
B2_QATU = b2_QATU;
}
public double getB2_CMUNIT() {
return B2_CMUNIT;
}
public void setB2_CMUNIT(double b2_CMUNIT) {
B2_CMUNIT = b2_CMUNIT;
}
public double getB2_VATU() {
return B2_VATU;
}
public void setB2_VATU(double b2_VATU) {
B2_VATU = b2_VATU;
}
public double getB2_QFIM() {
return B2_QFIM;
}
public void setB2_QFIM(double b2_QFIM) {
B2_QFIM = b2_QFIM;
}
public double getB2_VFIM() {
return B2_VFIM;
}
public void setB2_VFIM(double b2_VFIM) {
B2_VFIM = b2_VFIM;
}
public String getB2_DTFECHA() {
return B2_DTFECHA;
}
public void setB2_DTFECHA(String b2_DTFECHA) {
B2_DTFECHA = b2_DTFECHA;
}
public String getB2_DTULTINV() {
return B2_DTULTINV;
}
public void setB2_DTULTINV(String b2_DTULTINV) {
B2_DTULTINV = b2_DTULTINV;
}
public String getB2_DTCADASTRO() {
return B2_DTCADASTRO;
}
public void setB2_DTCADASTRO(String b2_DTCADASTRO) {
B2_DTCADASTRO = b2_DTCADASTRO;
}
public String getB2_ALTERA() {
return B2_ALTERA;
}
public void setB2_ALTERA(String b2_ALTERA) {
B2_ALTERA = b2_ALTERA;
}
public String getB2_DTINTEG() {
return B2_DTINTEG;
}
public void setB2_DTINTEG(String b2_DTINTEG) {
B2_DTINTEG = b2_DTINTEG;
}
}
Executei a alteração conforme orientado, agora a tabela esta sendo criada , porem a classe esta sendo criada sem relacionamento com a classe produtos, este relacionamento é fundamental para a modelagem.
Segue Nova classe Estoques
package entidades;
import java.io.Serializable;
import javax.persistence.Column;
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.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name = "SB2")
public class Estoques implements Serializable {
private static final long serialVersionUID = 5999236902534007386L;
@EmbeddedId
@JoinColumn(name = "B2_COD", referencedColumnName = "B1_COD")
private EstoquesPK id;
private int B2_QATU;
private double B2_CMUNIT;
private double B2_VATU;
private double B2_QFIM;
private double B2_VFIM;
@Column(length = 10)
private String B2_DTFECHA;
@Column(length = 10)
private String B2_DTULTINV;
@Column(length = 10)
private String B2_DTCADASTRO;
@Column(length = 10)
private String B2_ALTERA;
@Column(length = 10)
private String B2_DTINTEG;
public EstoquesPK getId() {
return id;
}
public void setId(EstoquesPK id) {
this.id = id;
}
public int getB2_QATU() {
return B2_QATU;
}
public void setB2_QATU(int b2_QATU) {
B2_QATU = b2_QATU;
}
public double getB2_CMUNIT() {
return B2_CMUNIT;
}
public void setB2_CMUNIT(double b2_CMUNIT) {
B2_CMUNIT = b2_CMUNIT;
}
public double getB2_VATU() {
return B2_VATU;
}
public void setB2_VATU(double b2_VATU) {
B2_VATU = b2_VATU;
}
public double getB2_QFIM() {
return B2_QFIM;
}
public void setB2_QFIM(double b2_QFIM) {
B2_QFIM = b2_QFIM;
}
public double getB2_VFIM() {
return B2_VFIM;
}
public void setB2_VFIM(double b2_VFIM) {
B2_VFIM = b2_VFIM;
}
public String getB2_DTFECHA() {
return B2_DTFECHA;
}
public void setB2_DTFECHA(String b2_DTFECHA) {
B2_DTFECHA = b2_DTFECHA;
}
public String getB2_DTULTINV() {
return B2_DTULTINV;
}
public void setB2_DTULTINV(String b2_DTULTINV) {
B2_DTULTINV = b2_DTULTINV;
}
public String getB2_DTCADASTRO() {
return B2_DTCADASTRO;
}
public void setB2_DTCADASTRO(String b2_DTCADASTRO) {
B2_DTCADASTRO = b2_DTCADASTRO;
}
public String getB2_ALTERA() {
return B2_ALTERA;
}
public void setB2_ALTERA(String b2_ALTERA) {
B2_ALTERA = b2_ALTERA;
}
public String getB2_DTINTEG() {
return B2_DTINTEG;
}
public void setB2_DTINTEG(String b2_DTINTEG) {
B2_DTINTEG = b2_DTINTEG;
}
}
Segue Nova Classe EstoquesPK
package entidades;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Embeddable;
@Embeddable
public class EstoquesPK implements Serializable {
private static final long serialVersionUID = -637018809489152388L;
@Column(length = 30)
private String B2_COD;
@Column(length = 2)
private String B2_LOCAL;
public String getB2_COD() {
return B2_COD;
}
public void setB2_COD(String b2_COD) {
B2_COD = b2_COD;
}
public String getB2_LOCAL() {
return B2_LOCAL;
}
public void setB2_LOCAL(String b2_LOCAL) {
B2_LOCAL = b2_LOCAL;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((B2_COD == null) ? 0 : B2_COD.hashCode());
result = prime * result + ((B2_LOCAL == null) ? 0 : B2_LOCAL.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
EstoquesPK other = (EstoquesPK) obj;
if (B2_COD == null) {
if (other.B2_COD != null)
return false;
} else if (!B2_COD.equals(other.B2_COD))
return false;
if (B2_LOCAL == null) {
if (other.B2_LOCAL != null)
return false;
} else if (!B2_LOCAL.equals(other.B2_LOCAL))
return false;
return true;
}
}
Estou apenas seguindo uma modelagem convencional.
É estranho ter uma classe de estoque sem relacionamento com produto, isso é um conceito básico.
Se fosse uma programação estruturada já estaria resolvido, mas o problema é que estamos falando de orientação a objetos, utilizando um conceito de relacionamento muito comum e que já existe a muitos anos.
Continuo na batalha para resolver o problema, mas até o momento só encontrei soluções paleativas
Isso é coisa de faculdade ou projeto pequeno. Melhor criar a tabela no banco sob seu controle. A partir daí faz o mapeamento conforme a necessidade, se realmente precisar usar JPA/Hibernate. Caso contrário use ferramentas mais leves e sob controle como JDBC Template da Spring. JPA/Hibernate tem muito overhead e enigmas pra situações fora do trilho, chave composta é uma dessas situações que o Hibernate suporta apenas para funcionar legados, nao para fazer bonito.