Chave Composta Campo Image SQLSERVER + JPA

Olá Amigos.

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.”

CREATE TABLE SB2 (
    ID IMAGE NOT NULL
    ,B2_ALTERA VARCHAR(10) NULL
    ,B2_CMUNIT FLOAT(32) NULL
    ,B2_DTCADASTRO VARCHAR(10) NULL
    ,B2_DTFECHA VARCHAR(10) NULL
    ,B2_DTINTEG VARCHAR(10) NULL
    ,B2_DTULTINV VARCHAR(10) NULL
    ,B2_QATU INTEGER NULL
    ,B2_QFIM FLOAT(32) NULL
    ,B2_VATU FLOAT(32) NULL
    ,B2_VFIM FLOAT(32) NULL
    ,PRIMARY KEY (ID)
    )

[Click e arraste para mover]

O problema é que o SQL não aceita campo IMAGE como chave primaria da tabela então retorna erro.

Segue abaixo as classe que estou criando.

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

@Embeddable
public class EstoquesPK implements Serializable {
    private static final long serialVersionUID = -637018809489152388L;
    
    @ManyToOne
    @JoinColumn(name = "B2_COD", referencedColumnName = "B1_COD")
    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;
    }
    
    

}

E abaixo a entidade

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "SB2")

public class Estoques implements Serializable {
    private static final long serialVersionUID = 5999236902534007386L;
    
    
    @EmbeddedId    
    @Id
    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;
    }

}

Espero que alguém consiga me ajudar estou com muita dificuldade nisso. Obrigado

Rapaz, não conhecia esse tipo, mas será que seria correto esse tipo ser usado como PK?

Ola Lucas.

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…

Nem falo do mapeamento, falo do script create mesmo: ID IMAGE NOT NULL.

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

Att:.

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.

1 curtida

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;
	}

}

Li seu código por alto e escrevi errado, mas quis dizer retirar isso aqui de “EstoquesPK”:

@ManyToOne
@JoinColumn(name = “B2_COD”, referencedColumnName = “B1_COD”)
private Produtos B2_COD;

E colocar esse atributo em Estoques com updatable = false.

“EstoquesPK” deixa só com os códigos String ou Integer conforme o tipo direto do banco.

E aqui se está usando chave composta, acho que nao precisa de @Id.

@EmbeddedId
private EstoquesPK id

1 curtida

Ola

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;
	}
		
}

Por curiosidade, vc está fazendo engenharia reversa para criar essas classes?

Não, não estou não.

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.