Search code examples
hibernatederby

Hibernate annotation mapping for One-To-Many bidirectional relation with DerbyDB


New with Hibernate, I'm trying to achieve a very simple task but ending up round in circles with number of erros.

Two tables Cart and Items with One-To-Many relation. I want to call save on the parent table entity and expect child table to get saved as well.

enter image description here

Script 1:

CREATE TABLE cart
(
    cart_id INTEGER NOT NULL, 
    reference_number INTEGER,
    PRIMARY KEY (cart_id)
);

CREATE TABLE item
(
    item_id INTEGER NOT NULL,
    cart_id INTEGER NOT NULL,
    name Varchar(255) ,
    description Varchar(255) ,
    PRIMARY KEY (item_id),
    FOREIGN KEY (cart_id) REFERENCES cart
);

Using hibernate code generation following are the Entity classes.

@Entity
@Table(name = "CART", schema = "MYSCHEMA")
public class Cart implements java.io.Serializable {

    private int cartId;
    private Integer referenceNumber;
    private List<Item> items = new ArrayList<Item>();

    @Id
    @Column(name = "CART_ID", unique = true, nullable = false)
    public int getCartId() {
        return this.cartId;
    }

    @OneToMany(mappedBy = "cart", cascade = CascadeType.ALL, orphanRemoval = true)
    public List<Item> getItems() {
        return items;
    }

    public void addItem(Item item) {
        items.add(item);
        item.setCart(this);
    }

    public void removeComment(Item item) {
        items.remove(item);
        item.setCart(this);
    }

    public void setItems(List<Item> items) {
        this.items = items;
    }

    // Excluding rest of the Getters and Setterss
}


@Entity
@Table(name = "ITEM", schema = "MYSCHEMA")
public class Item implements java.io.Serializable {

    private int itemId;
    private int cartId;
    private String name;
    private String description;
    private Cart cart;

    @Id
    @Column(name = "ITEM_ID", unique = true, nullable = false)
    public int getItemId() {
        return this.itemId;
    }

    @ManyToOne
    @JoinColumn(name = "cart_id", nullable = false, insertable = false, updatable = false)
    public Cart getCart() {
        return cart;
    }

    public void setCart(Cart cart) {
        cart = cart;
    }

    // Excluding rest of the Getters and Setterss
}

With this setting when run following.

    Session session = HibernateUtil.getSessionFactory().openSession();
    session.beginTransaction();

    Cart cart = new Cart();
    cart.setReferenceNumber(333);

    Item item1 = new Item();
    item1.setName("itemONe");
    item1.setDescription("itemOneDescription");
    item1.setCart(cart);
    cart.addItem(item1);

    Item item2 = new Item();
    item2.setName("itemONe");
    item2.setDescription("itemOneDescription");
    item2.setCart(cart);
    cart.addItem(item2);

    session.save(cart);
    session.getTransaction().commit();

It gives following error .

Exception in thread "main" org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [com.testHibernate.models.Item#0]

Which makes sence as neither Hibernate nor Database is handling the auto generation of Primary key. So, If I run the above code with with Item1 only it works and saves both records.

For Generating ID via Database if I change my DB to following

Script 2:

CREATE TABLE cart
(
    cart_id INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1), 
    reference_number INTEGER,
    PRIMARY KEY (cart_id)
);

CREATE TABLE item
(
    item_id INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
    cart_id INTEGER NOT NULL,
    name Varchar(255) ,
    description Varchar(255) ,
    PRIMARY KEY (item_id),
    FOREIGN KEY (cart_id) REFERENCES cart
);

Keeping the Entity classes same as shown above, it has no effect. Same Error comes up.

I tried using the @GeneratedValue(strategy = GenerationType.IDENTITY) with the PrimeryKey fields in both classes and the following error shows up on save.

ERROR: INSERT on table 'ITEM' caused a violation of foreign key constraint 'SQL0000000002-06ba0cd1-016e-2cf2-dad9-ffff908894b5' for key (0). The statement has been rolled back.

Isn't Hibernate supposed to handle this with cascade = CascadeType.ALL?

What am i missing ?

Hibernate v5.4.4 Derby DB v10.15.1.3


Solution

  • In the first case you have 2 item entities with the same ID - zero.

    For the 2nd error, how do you expect the non nullable foreign key column cart_id to be set when you have defined the join column as insertable = false, updatable = false? Remove these attributes and it should work.