Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Persist collection of interface using Hibernate

I want to persist my litte zoo with Hibernate:

@Entity @Table(name = "zoo")  public class Zoo {     @OneToMany     private Set<Animal> animals = new HashSet<Animal>(); }  // Just a marker interface public interface Animal { }  @Entity @Table(name = "dog") public class Dog implements Animal {     // ID and other properties }  @Entity @Table(name = "cat") public class Cat implements Animal {     // ID and other properties } 

When I try to persist the zoo, Hibernate complains:

Use of @OneToMany or @ManyToMany targeting an unmapped class: blubb.Zoo.animals[blubb.Animal] 

I know about the targetEntity-property of @OneToMany but that would mean, only Dogs OR Cats can live in my zoo.

Is there any way to persist a collection of an interface, which has several implementations, with Hibernate?

like image 253
Olvagor Avatar asked May 26 '10 12:05

Olvagor


People also ask

How do you persist objects in Hibernate?

All classes should contain an ID in order to allow easy identification of your objects within Hibernate and the database. This property maps to the primary key column of a database table. All attributes that will be persisted should be declared private and have getXXX and setXXX methods defined in the JavaBean style.

What is the difference between Merge and persist in Hibernate?

Persist should be called only on new entities, while merge is meant to reattach detached entities. If you're using the assigned generator, using merge instead of persist can cause a redundant SQL statement.

How do I persist a list in JPA?

Solution: Since JPA 2.0, you can use an element collection to persist a Collection of value types. You just need to annotate the attribute with @ElementCollection and the persistence provider will persist the elements of the Collection in an additional database table.


2 Answers

JPA annotations are not supported on interfaces. From Java Persistence with Hibernate (p.210):

Note that the JPA specification doesn’t support any mapping annotation on an interface! This will be resolved in a future version of the specification; when you read this book, it will probably be possible with Hibernate Annotations.

A possible solution would be to use an abstract Entity with a TABLE_PER_CLASS inheritance strategy (because you can't use a mapped superclass - which is not an entity - in associations). Something like this:

@Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) public abstract class AbstractAnimal {     @Id @GeneratedValue(strategy = GenerationType.TABLE)     private Long id;     ... }  @Entity public class Lion extends AbstractAnimal implements Animal {     ... }  @Entity public class Tiger extends AbstractAnimal implements Animal {     ... }  @Entity public class Zoo {     @Id @GeneratedValue     private Long id;      @OneToMany(targetEntity = AbstractAnimal.class)     private Set<Animal> animals = new HashSet<Animal>();      ... } 

But there is not much advantages in keeping the interface IMO (and actually, I think persistent classes should be concrete).

References

  • Annotations, inheritance and interfaces
  • using MappedSuperclass in relation one to many
  • Polymorphic association to a MappedSuperclass throws exception
like image 56
Pascal Thivent Avatar answered Sep 18 '22 15:09

Pascal Thivent


I can guess that what you want is mapping of inheritance tree. @Inheritance annotation is the way to go. I don't know if it will work with interfaces, but it will definitely work with abstract classes.

like image 32
yatskevich Avatar answered Sep 18 '22 15:09

yatskevich