@EmbeddedId + @OneToMany

Boa noite pessoal!
tenho a seguinte estrutura de tabelas:

VENDA

  • venda_id auto_increment pk

ITEM_VENDA

  • item_id /funcionna como uma ordem, sempre de 0…N/
  • venda_id

pk(item_id, venda_id)
fk(venda_id)

classes:

Venda:

public class Venda implements Serializable {
    @Id
    @GeneratedValue
    @Column(name = "VENDA_ID", nullable = false)
    private Integer vendaId;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "venda")
    private Collection<ItemVenda> itemVendaCollection;
    ...

ItemVenda:

public class ItemVenda implements Serializable {
    @EmbeddedId
    /*Encapsula ItemId e VendaId */
    protected ItemVendaPK itemVendaPK;
    ...

Quando tento salvar ocorre o seguinte problema:
"Cannot add or update a child row: a foreign key constraint fails … FOREIGN KEY (VENDA_ID) REFERENCES venda (VENDA_ID)"
Isso ocorre porque eu seto somente o campo itemVendaPK.itemId.

O que eu esperava que acontecesse, era que o Hibernate ja configurasse o campo itemVendaPK.vendaId
automaticamente, sem eu precisar gravar primeiro a venda e depois os itens separadamente.

Alguem pode me ajudar?

Desde já grato!

Geraldo,

Altere suas classes desta forma que acredito que vai funcionar.

@Entity
public class Venda implements Serializable {   
    @Id   
    @GeneratedValue   
    @Column(name = "VENDA_ID", nullable = false)   
    private int vendaId;  
 
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "venda")   
    private Collection<ItemVenda> itemVendaCollection;   

    // Métodos acessores omitidos
    ...
    ...
    ...

}

@Entity
@IdClass(ItemVendaPK.class)
public class ItemVenda implements Serializable {   
    @Id
    @Column(name = "ITEM_VENDA_ID", nullable = false)
    private int itemVendaId; 

    @Id
    @Column(name = "VENDA_ID", nullable = false)
    private int VendaId;  

    @ManyToOne  
    @JoinColumn(name = "VENDA_ID", referencedColumnName = "VENDA_ID", nullable = false)   
    private Venda venda; 


    // Métodos acessores omitidos
    ...
    ...
    ...
}

public class ItemVendaPK implements Serializable {   
    @Column(name="VENDA_ID")   
    private int vendaId;   
    @Column(name="ITEM_VENDA_ID")   
    private int itemVendaId;
  
    // Métodos acessores omitidos   
    ....   
    ....
    ....
} 

@braços,
Cleiton

Bom dia Cleiton!
Cara, devo estar fazendo alguma coisa errada.
Veja só o código exatamente como estou tentando.

@Entity
public class Venda implements Serializable {
    @Id
    @Column(name = "VENDA_ID", nullable = false)
    @GeneratedValue
    private Integer vendaId;
    @Column(name = "TOTAL_VENDA", nullable = false)
    private BigDecimal totalVenda;
    @OneToMany(cascade = CascadeType.ALL , mappedBy = "venda"  )
    private List<ItemVenda> itemVendaList;
    ...
}


@Entity
@Table(name = "item_venda")
@IdClass(ItemVendaPK.class)
public class ItemVenda implements Serializable {
    @Id
    @Column(name = "ITEM_ID", nullable = false)
    private Integer itemId;
    @Id
    @Column(name = "VENDA_ID", nullable = false)
    private Integer vendaId;
    @Column(name = "PRODUTO_ID", nullable = false)
    private int produtoId;
    @Column(name = "QUANTIDADE", nullable = false)
    private BigDecimal quantidade;
    @Column(name = "PRECO", nullable = false)
    private BigDecimal preco;
    @Column(name = "PRECO_TOTAL", nullable = false)
    private BigDecimal precoTotal;
    @JoinColumn(name = "VENDA_ID", referencedColumnName = "VENDA_ID", nullable = false)
    @ManyToOne
    private Venda venda;
    ...
}

/*Removi o @Embeddable daqui*/
public class ItemVendaPK implements Serializable {
    @Column(name = "ITEM_ID", nullable = false)
    private Integer itemId;
    @Column(name = "VENDA_ID", nullable = false)
    private Integer vendaId;
    ...
}

public class Main {
    public static void main(String[] args) {
        try {

            Venda v = new Venda();
            v.setTotalVenda(BigDecimal.valueOf(45));

            ItemVenda i1 = new ItemVenda();
            i1.setItemId(0);
            i1.setProdutoId(13);
            i1.setPreco(BigDecimal.valueOf(14));
            i1.setQuantidade(BigDecimal.valueOf(5));
            i1.setPrecoTotal(BigDecimal.valueOf(450));

            ItemVenda i2 = new ItemVenda();
            i2.setItemId(1);
            i2.setProdutoId(130);
            i2.setPreco(BigDecimal.valueOf(104));
            i2.setQuantidade(BigDecimal.valueOf(50));
            i2.setPrecoTotal(BigDecimal.valueOf(40));
            
            i1.setVenda(v);
            i2.setVenda(v);

            ArrayList a = new ArrayList();
            a.add(i1);
            a.add(i2);

            v.setItemVendaList(a);

            JPAUtil.persist(v);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

e aqui a mensagem:

Hibernate: insert into venda (TOTAL_VENDA) values (?)
Hibernate: insert into item_venda (PRECO, PRECO_TOTAL, PRODUTO_ID, QUANTIDADE, ITEM_ID, VENDA_ID) values (?, ?, ?, ?, ?, ?)
27/10/2007 12:05:48 org.hibernate.type.NullableType nullSafeSet
INFO: could not bind value ‘null’ to parameter: 7; Parameter index out of range (7 > number of parameters, which is 6).


org.hibernate.exception.GenericJDBCException: could not insert: [appTeste.ItemVenda]


Caused by: java.sql.SQLException: Parameter index out of range (7 > number of parameters, which is 6).

Geraldo,

Altere a anotação na sua classe ItemVenda para:

    ....
    ....
    ....
    @Id
    @Column(name = "VENDA_ID", nullable = false, insertable=false, updatable=false)
    private Integer vendaId;

    ....
    ....
    ....

    @JoinColumn(name = "VENDA_ID", referencedColumnName = "VENDA_ID", insertable = false, updatable = false)
    @ManyToOne
    private Venda venda;
    ....
    ....
    ....

@braços,
Cleiton

Mesmo assim não funcionou,
já não tenho tempo pra ficar ralando com isso, vou deixar do jeito tá,
quando tiver um tempo, volto a tentar.

Cleiton, obrigado mesmo pelo tempo e atenção cedidos!

Beleza amigo?

Cara, não desiste tão rápido. Quando eu aprendia as coisas, levava era dias a fio. E olha que Java, na minha época, num era essa baba de ter tantos livros e revistas espalhadas por ai (sem contar escolas e profissionais bons).
Bom, dei uma olhada por cima, e acredito que você ainda precisa alterar algumas coisas:



@Entity
@Table(name = "item_venda")
@IdClass(ItemVendaPK.class)
public class ItemVenda implements Serializable {

//eu não utilizaria, pq já está no Embeddable 
  // @Id
//    @Column(name = "ITEM_ID", nullable = false)
 //   private Integer itemId;


  //  @Id
  //  @Column(name = "VENDA_ID", nullable = false)
  //  private Integer vendaId;

//adicionei o EmbeddedId
    @EmbeddedId
    private ItemVendaPK id;



    @Column(name = "PRODUTO_ID", nullable = false)
    private int produtoId;
    @Column(name = "QUANTIDADE", nullable = false)
    private BigDecimal quantidade;
    @Column(name = "PRECO", nullable = false)
    private BigDecimal preco;
    @Column(name = "PRECO_TOTAL", nullable = false)
    private BigDecimal precoTotal;
    @JoinColumn(name = "VENDA_ID", referencedColumnName = "VENDA_ID", nullable = false)
    @ManyToOne
    private Venda venda;
    ...
}


public class ItemVendaPK implements Serializable {
    @Column(name = "ITEM_ID", nullable = false)
    private Integer itemId;
    @Column(name = "VENDA_ID", nullable = false)
    private Integer vendaId;
    ...
}

Boa noite ajaxinaction!

Espero que assim funcione, mas eu não desisti não, contrário disso, estou
cada vez mais ansioso pra fazer isso funcionar, mas eh que realmente estou
sem tempo. Amanhã tirarei um tempo pra fazer esse teste e certamente postarei aqui o resultado.

Creio que ainda mais importante do que livros, revistas e etc., são forums
como esse, e com pessoas interessadas a compartilhar o conhecimento.

Estou realmente muito grato,

Um abraço!

[quote=Geraldo Eliezer]Boa noite ajaxinaction!

Espero que assim funcione, mas eu não desisti não, contrário disso, estou
cada vez mais ansioso pra fazer isso funcionar, mas eh que realmente estou
sem tempo. Amanhã tirarei um tempo pra fazer esse teste e certamente postarei aqui o resultado.

Creio que ainda mais importante do que livros, revistas e etc., são forums
como esse, e com pessoas interessadas a compartilhar o conhecimento.

Estou realmente muito grato,

Um abraço![/quote]

Belezinha Geraldo?

Gostaria de saber se resolveu seu problema? To com um problema parecido.

Valeu

Olá pessoal,

Eu perguntei ao colega mas eu mesmo já resolvi. A dica do ajaxinaction tá correta. Era isso mesmo.

Obrigado pela dica e fica ai, caso alguém também tenha essa dúvida, que eu resolvi.

Estou fazendo uma sistema que vai possir um relacionamento @OneToMany
mais estou com duvidas de como devera ficar no banco de dados,
se alguem poder me mostra como fica o relacionamento FICO MUITO GRATO!

EX: Tenho uma tabela Venda, Produto. A tabela venda vai ter uma lista de produtos

Eu estava com o seguinte problema

Venda – @OneToMany – ItemVenda

porém ItemVenda não possui Pk, mas possui Fk referenciando a Pk da entidade Venda.

exemplo de como as tabelas foram criadas no bd manualmente.


CREATE TABLE "HR"."MSS_VENDA" (	
	"VENDA_ID" NUMBER(10,0)      NOT NULL ENABLE,
	"NOME"      VARCHAR2(64 BYTE) NOT NULL ENABLE, 
	CONSTRAINT "MSSVENDA_PK" PRIMARY KEY ("VENDA_ID")
 );

CREATE TABLE "HR"."MSS_ITEM_VENDA" (
	"VENDA_ID" NUMBER(10,0)      NOT NULL ENABLE,
	"CONTATO"   VARCHAR2(64 BYTE) NOT NULL ENABLE, 
	CONSTRAINT "MSSITEMVENDA_FK" FOREIGN KEY ("VENDA_ID")
	REFERENCES "HR"."MSS_VENDA" ("VENDA_ID") ON DELETE CASCADE ENABLE
);

A ultima correção que o ajaxinaction postou funcionou perfeito para meu cenario, onde as tabelas já estavam previamente criadas da maneira como falei acima.

Se eu mando o JPA criar as tabelas a partir das entidades acontece um erro de integridade, não sei direito o porque, acredito que seja pq o JPA quando cria a tabela da entidade ItemVenda coloca a Fk também como Pk.

@Geraldo_Eliezer Coloca o
@MapsId(“id_pk”)
@OneToMany(cascade = CascadeType.ALL, mappedBy = “venda”)
http://www.objectdb.com/api/java/jpa/MapsId