2

I have an entity Customer with an @ElementCollection annotation:

@Entity
@Table(name = "customer")
public class Customer {
  @Id
  @Column(name = "id")
  @GeneratedValue(strategy= GenerationType.AUTO)
  private Long id;

  @ElementCollection
  @CollectionTable(name = "customer_alias", joinColumns = @JoinColumn(name = "customer_id") )
  @Column(name = "alias")
  private List<String> aliases;

}

The table customer_alias contains a few rows when I start my app. In my code I have a loop that iterates the aliases:

for(String alias: customer.getAliases()) { ... }

Strangely, right after this line I see in the log these 2 lines:

Hibernate: select aliases0_.customer_id as cus1_3_0_, aliases0_.aliase as ali2_0_0_ from customer_alias aliases0_ where aliases0_.customer_id=?
Hibernate: delete from customer_alias where customer_id=?

Of course - after the 'delete' line the data is deleted from the DB and I can't figure out why. There's no where in my code where I call delete and it happens right after the for loop. It looks like when I call getAliases() it deletes the table.

Avi
  • 21,182
  • 26
  • 82
  • 121
  • 1
    What's in your for loop? – Henry Apr 09 '16 at 09:02
  • 1
    Maybe it's related to this: http://stackoverflow.com/questions/3742897/hibernate-elementcollection-strange-delete-insert-behavior – jon martin solaas Apr 09 '16 at 09:17
  • @Henry - I put in the loop only this line - `System.out.println("Test");` to make sure it happens on the loop and not inside the loop. Still happens – Avi Apr 09 '16 at 09:25
  • @jonmartinsolaas - Thanks for the reference. I visited this question yesterday but it doesn't seem all that related. In my case I don't call delete or insert anywhere. Also I made suer I have a primary key on the alias table. – Avi Apr 09 '16 at 09:26
  • You don't have to call delete or insert for this to happen. The point is - when Hibernate gets confused about identity of the elements, it will delete ALL, and then insert ALL from the Entity holding the collection, when one element is dirty, or possibly dirty, because it does not know which single row in the table to update. For further confusion, this is implemented so that insert happens before delete unless you put a clever flush-statement in a suitable place. If not, and you have a unique index on the table, you'll get a constraint violation. This might, or might not, be your problem :o) – jon martin solaas Apr 09 '16 at 09:49

2 Answers2

0

Unfortunatelly, after reading posts and the referred answer from the comments I could not find a solution that works. I resolved it by creating an entity Alias, with a primary key and @Id field.

Leaving this answer for reference without accepting it in the hope of a better solution in the future.

Avi
  • 21,182
  • 26
  • 82
  • 121
0

From https://en.wikibooks.org/wiki/Java_Persistence/ElementCollection

The JPA 2.0 specification does not provide a way to define the Id in the Embeddable. However, to delete or update a element of the ElementCollection mapping, some unique key is normally required. Otherwise, on every update the JPA provider would need to delete everything from the CollectionTable for the Entity, and then insert the values back. So, the JPA provider will most likely assume that the combination of all of the fields in the Embeddable are unique, in combination with the foreign key (JoinColumn(s)). This however could be inefficient, or just not feasible if the Embeddable is big, or complex.

Some JPA providers may allow the Id to be specified in the Embeddable, to resolve this issue. Note in this case the Id only needs to be unique for the collection, not the table, as the foreign key is included. Some may also allow the unique option on the CollectionTable to be used for this. Otherwise, if your Embeddable is complex, you may consider making it an Entity and use a OneToMany instead.

Community
  • 1
  • 1
  • Yep, it was referenced in the comments, and I also found it myself. It doesn't solve the issue or at least I can't understand what I should change in order to solve the issue. It just explains the reason behind it, nothing neither in this paragraph or other answers gave a working solution unfortunatelly :/ – Avi Apr 10 '16 at 21:20
  • I understand, theoretically, you cant prevent deletion of entries in table unless you have some mapping of tables as OneToMany has. may be use a OneToMany or implement OneToMany as ElementCollection by writing Entity class methods to expose same API as ElementCollection. I hope I am clear for second choice – meet thakkar Apr 10 '16 at 21:29