使用Hibernate持久化接口集合

31

我想使用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
}

当我尝试持久化动物园时,Hibernate 报错:

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

我知道@OneToManytargetEntity属性,但这意味着我的动物园里只能有狗或者猫。

是否有一种方法可以使用Hibernate持久化一个包含多个实现的接口集合?

3个回答

31
JPA注释不支持在接口上使用。来自《Java Persistence with Hibernate》(第210页)的内容:
请注意,JPA规范不支持在接口上使用任何映射注释!这将在未来版本的规范中解决;当您阅读本书时,可能可以使用Hibernate Annotations。
一个可能的解决方案是使用具有TABLE_PER_CLASS继承策略的抽象实体(因为您不能在关联中使用映射超类 - 它不是实体)。像这样:
@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>();

    ...
}

但是在我看来,保留接口并没有太多优势(实际上,我认为持久化类应该是具体的)。

参考资料


事实上,我的真正问题比上面的问题要复杂得多,所以你的答案在我的情况下不起作用。但它看起来是对我的问题的正确回答,所以我会接受它。谢谢! - Olvagor
1
你有没有想过为什么抽象类 AbstractAnimal 没有实现接口 Animal - maxxyme
@Pascal,我尝试了这个方法,但是似乎需要一个AbstractAnimal表的表格,这并不理想,但我可以接受。然而,在Animal插入发生后,Animal需要引用一个动物园,但由于更新针对的是AbstractAnimal而不是具体的动物,所以失败了。 - ssc327

1
我可以猜到你想要的是继承树的映射。 @Inheritance 注释就是正确的选择。 我不知道它是否适用于接口,但肯定适用于抽象类。

我会尝试这个,如果不行的话就使用抽象类。 - Olvagor
是的,抽象类是更好的解决方案。就像Péter Török已经说过的那样,您可以将id和其他共同属性放到Animal类中。 - yatskevich

0

我认为您还需要在接口上使用@Entity进行注释,并且我们必须在接口的所有getter和setter上注释@Transient


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接