JPA Hibernate :: FK + Chave Composta

Olá. Meu primeiro post nesse fórum.
Estou iniciando um projeto onde o banco já foi construído (sem possibilidades de alteração) e tem chaves compostas para todo lado.

Não estou conseguindo fazer um simples relacionamento entre duas tabelas, onde uma FK faz parte da chave composta da segunda tabela. Segue Código:

Vamos partir da idéia que uma EMPRESA (tabela) tem vários SETORES (outra tabela)

CLASSE EMPRESA:

@Entity
public class Empresa implements Serializable {

	@Id
	@Column(name = "IDENTIDADE")
	private Long id;

	@Column(name = "NOME")
	private String nome;

//Aqui o relaciomento com um campo que faz parte da PK
	@OneToMany(targetEntity = Setor.class, mappedBy = "empresa")
	private Set<Setor> setores = new HashSet<Setor>();

//getters e setters da classe

} //fim da classe Empresa

AGORA O RELACIONAMENTO ENTRE O SETOR
CLASSE SETOR:

public class Setor implements Serializable {

	@Embeddable
	static class SetorPK implements Serializable {
       // ### Aqui está minha FK, dentro da PK ######
		@ManyToOne(targetEntity = Empresa.class)
		private Empresa empresa;

		@Column(name = "SETOR", nullable = false, length = 20)
		private String setor;

        //getters setters da classe interna
        }
       
        @EmbeddedId
	private SetorPK id;

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

//getters e setters da classe concreta

}// fim da classe Setor

Reparem que na classe Setor, a Empresa faz parte da chave (fogo trabalhar com chaves compostas)
Bem, a JPA (estou usando a implementação do Hibernate) não permite uma FK fazer parte da PK … ou seja, se eu tirar a Empresa da PK funciona perfeitamente, mas não posso já q o maldito banco está pronto !!!

Alguém pode me dar uma idéia de contornar esse problema???

Obrigado!

Júnior

Tenta usar somente o id da empresa ao invés de utilizar uma agregação com a classe empresa.
Ex.:

@Column(name = "cod_empresa", nullable = false, length = 20)
private Long empresaId;

Já trabalhei com chaves compostas, é um saco…
em caso de bancos de dados muito complexos, não recomendo a utilização de frameworks para persistência dos dados.

Hum… interessante, mas depois pelo Setor eu poderei recuperar a Empresa???

Esse banco já foi projetado há um ano e vários outros sistemas q estão em desenvolvimento avançado já utilizam esse “padrão” de banco… mania de delphizeiro criar o banco primeiro para depois construir as telinhas…

Caso eu sinta q não dê para usar JPA (oq é quase certo) acho q vou ter q mapear as classes x tabelas por arquivos hbm… dá-lhe xml pra todo lado… hehehehe

Mas obrigado pela atenção.

Júnior

Sim, neste caso, a sua chave estrangeira é composta também, mas aí já é mais fácil resolver! Pra vc ter idéia, eu já peguei chave composta por 5 campos :wink: mas o banco era tão doido que foi muito mais prático fazer usando só jdbc mesmo!

Boa sorte em sua jornada

Oi M0ska… primeiramente, muito obrigado pela atenção!!!

Quase deu certo… só q estavam sendo lançadas umas excessões, então resolvi fazer um teste:
Criei um banco novo e vazio (sem tabelas)
Ajustei o updateSchema para “true” e executei a aplicação para q o Hibernate criasse as tabelas.

Eu esperava que o banco fosse criado igual à estrutura do banco oficial… e para minha surpresa não foi isso q aconteceu…

Na parte do relacionamento em questão, o Hibernate criou uma tabela de junção entre Empresa e Setores, ficando assim:

|Empresa -> <-- Empresa_Setor --> <- Setor |

E esperava que houvesse um relacionamento direto entre Setor.empresaId = Empresa.id
Mesmo eu colocando o @ColumnName iguais e uma apontando para o outro…
muito estranho… será q estou fazendo errado, ou o modelo do banco “padrão” está errado!!!

to quase migrando para os hbm.xml …

Obrigado!!!

Júnior

Consegui resolver… fazendo um relacionamento bidirecional…
colocando um ManyToOne num lado e OneToMany em outro lado… daí deu certo!

Obrigado m0ska, valeu!

Júnior

Ae Junior, blza. Eu estou com o seguinte problema, veja o código primeiro:

ESSE É O ENTITY DO AGENT

@OneToMany(cascade=CascadeType.ALL,mappedBy="agent")
private List<ContactAgent> listContact = new ArrayList<ContactAgent>();

ESSE É O ENTITY CONTACTAGENT

@ManyToOne(cascade=CascadeType.PERSIST)
@JoinColumn(name="AGENTUID")
private Agent agent;

O entity do Agent é o principal, é através dele que eu quero salvar o entity do ContactAgent. Antes de persistir eu adiciono todos os ContactAgent`s que eu quero no entity do Agent e do um persit no entity do Agent. Na base de dados os registros salvam normal menos na tabela do ContactAgent que salva todos os campos menos o atributo agentUid, esse atributo fica nulo. Já perdi bastantes noites de sono por causa desse cara… Alguém já passou por isso?

Meninos,

Estou com um problema parecido com o de vocês e gostaria de pedir uma ajuda.

Tenho 2 classes:

Essa é a requisito_erp.

@Entity
@Table(name = “requisitos_erp”)
@NamedQueries({@NamedQuery(name = “RequisitosErp.findAll”, query = “SELECT r FROM RequisitosErp r”),
@NamedQuery(name = “RequisitosErp.findByIdBts”, query = “SELECT r FROM RequisitosErp r WHERE r.requisitosErpPK.idBts = :idBts”),
@NamedQuery(name = “RequisitosErp.findByIdCap”, query = “SELECT r FROM RequisitosErp r WHERE r.requisitosErpPK.idCap = :idCap”),
@NamedQuery(name = “RequisitosErp.findByIdSubcap”, query = “SELECT r FROM RequisitosErp r WHERE r.requisitosErpPK.idSubcap = :idSubcap”),
@NamedQuery(name = “obterRequisitoPelaChave”,query = “SELECT r FROM RequisitosErp r WHERE r.requisitosErpPK.idBts = :idBts and r.requisitosErpPK.idCap = :idCap and r.requisitosErpPK.idSubcap = :idSubcap and r.requisitosErpPK.doc = :doc”),
@NamedQuery(name = “RequisitosErp.RequisitoERP”,query = “SELECT r FROM RequisitosErp r WHERE r.requisitosErpPK.idBts = :idBts and r.requisitosErpPK.idCap = :idCap and r.requisitosErpPK.idSubcap = :idSubcap”),
@NamedQuery(name = “RequisitosErp.findByDoc”, query = “SELECT r FROM RequisitosErp r WHERE r.requisitosErpPK.doc = :doc”)})
public class RequisitosErp implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId
protected RequisitosErpPK requisitosErpPK;
@Basic(optional = false)
@Lob
@Column(name = “requisito”)
private String requisito;

Essa é a requisito_erp_Pk

@Embeddable
public class RequisitosErpPK implements Serializable {
@Basic(optional = false)
@Column(name = “id_bts”)
private long idBts;
@Basic(optional = false)
@Column(name = “id_cap”)
private int idCap;
@Basic(optional = false)
@Column(name = “id_subcap”)
private int idSubcap;
@Basic(optional = false)
@Column(name = “doc”)
private String doc;

E eu preciso fazer uma função para remover um registro dessa tabela.

Só que ja tentei várias formas e não funciona.

Veja um dos exemplos:

public String imgExcluir_action() {
long id_bts_erp = (Long) stIdBts.getValue();
int id_cap_erp = (Integer) stidCap.getValue();
int sub_cap_erp = (Integer) stIdSubcap.getValue();
String docERP;
String Requisito;

     docERP = (String) stDocERP.getText();
     Requisito = stRequisito.getText().toString();

 
     RequisitosErp requisitoerp = new RequisitosErp();
      requisitoerp.setRequisito(Requisito);

     RequisitosErpPK pk = new RequisitosErpPK();
       pk.setIdBts(id_bts_erp);
       pk.setIdCap(id_cap_erp);
       pk.setIdSubcap(sub_cap_erp);
       pk.setDoc(docERP);

      requisitoerp.setRequisitosErpPK(pk);


    RequisitosERPDAO ExcluirRequisitoDAO = new RequisitosERPDAO();
    try {
        ExcluirRequisitoDAO.Excluir(requisitoerp);
        info("Requisito excluído com sucesso!");
    } catch (Exception e) {
        info("Erro - Requisito não pôde ser excluído!");
    }
     return "CapituloEdicao";
}

public void Excluir(RequisitosErp requisitoerp) {
EntityManager em = Conecta.getEntityManager();
try {
EntityTransaction utx = em.getTransaction();
RequisitosErp requisitoERP = em.find(RequisitosErp.class,requisitoerp);

        utx.begin();
        em.remove(requisitoerp);
        utx.commit();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        em.close();
    }
}

Só que dessa forma não funciona.Alguém poderia me ajudar numa possivel solução.

Obrigada.