0

My classes look simiar to this: (Offer class)

@Entity
public class Offer {
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private int id;
    @ElementCollection(fetch = FetchType.LAZY)
    private Set<Product> products;

    ...other fields
}

and Product class:

@Embeddable
public class Product {
    private String name;
    private String description;
    private int amount;
}

The problem is when I try to persist the Offer entity and try to add two objects to Offer's Set:

Product product = new Product("ham", "description1", 1);
Product product = new Product("cheese", "description2", 1);

I receive exception:

Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "offer_products_pkey"
  Details: Key (offer_id, amount)=(1, 1) already exists.

I have no idea why can't I persist two embeddable objects in the Set when one of them has the same value of "amount" field? Is it treated as ID somehow?

Maybe I should not create list of embeddable objects as it is not designed to be used like this? If so - then what if I dont need an entity of Product but want to keep set of it in another entity (Offer)?

Thanks in advance for help

azalut
  • 4,094
  • 7
  • 33
  • 46
  • 1
    You have probably wrong defined key in table Products. Exception is clear – mariusz2108 May 02 '16 at 16:46
  • I dont have any key variable in Product object. If I use List instead of Set it works fine, but for Set it does not. Problem seems to be bound up with features of Set interface - it cannot contain duplicates. But why is field "amount" treated as duplicate? – azalut May 02 '16 at 16:52
  • The error comes from PostgreSQL. It tells you what is wrong: you have defined what looks like a primary key named offer_products_pkey for (offer_id, amount). And you're trying to insert two rows with the same primary key. drop that primary key constraint if it shouldn't exist. – JB Nizet May 02 '16 at 18:18

1 Answers1

0

The issue when using a Set is that the contents must be unique, since that is the definition of a Set. The JPA provider will try to enforce this with a database constraint. In your example it adds a constraint in the form of a Primary Key the Offer_id and the int Amount, though IMHO it should be adding a constraint for all the values of Product property. The best way to see this is to enable the SQL logs and see what is going on under the covers:

Hibernate: create table Offer (id integer not null, primary key (id))
Hibernate: create table Offer_products (Offer_id integer not null, amount integer not null, description varchar(255), name varchar(255), primary key (Offer_id, amount))
Hibernate: alter table Offer_products add constraint FKmveai2l6gf4n38tuhcddby3tv foreign key (Offer_id) references Offer

The way to fix this is to make the products property of Offer a List instead of the Set:

Hibernate: create table Offer (id integer not null, primary key (id))
Hibernate: create table Offer_products (Offer_id integer not null, amount integer not null, description varchar(255), name varchar(255))
Hibernate: alter table Offer_products add constraint FKmveai2l6gf4n38tuhcddby3tv foreign key (Offer_id) references Offer
K.Nicholas
  • 10,956
  • 4
  • 46
  • 66