Chave Composta Campo Image SQLSERVER + JPA

11 respostas
E

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

11 Respostas

Lucas_Camara

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

E

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…

Lucas_Camara

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

E

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

javaflex

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.

E

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

}
javaflex

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

E

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

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

E

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

javaflex

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.

Criado 24 de julho de 2020
Ultima resposta 28 de jul. de 2020
Respostas 11
Participantes 3