如何使用继承处理JPA CollectionTable?

时间:2016-10-13 11:48:14

标签: java hibernate jpa

我必须创建一个类的层次结构,其中一个超类具有表示地图的@CollectionTable。我试图实现它,但它只适用于一个子类。

我想做以下事情。我左边是当前结构,右边是所需结构。 UML diagram of the structure

稳定(工作)代码如下所示:

@MappedSuperclass
public class Animal {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", updatable = false, nullable = false)
    private Long id;
}

@Entity(name = "cats")
@Audited
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.CHAR)
@DiscriminatorValue(value = Cat.PET_TYPE)
public abstract class Cat extends Animal {
    public static final String PET_TYPE = "C";

    @ElementCollection(fetch = FetchType.EAGER)
    @MapKeyColumn(name = "name")
    @Column(name = "value")
    @CollectionTable(name = "cat_properties", joinColumns = @JoinColumn(name = "cat_id"))
    private Map<String, String> properties = new HashMap<>();
}

@Audited
@Entity(name = "persiancats")
@DiscriminatorValue(value = PersianCat.PERSIAN_CAT_TYPE)
public class PersianCat extends Cat {
    public static final String PERSIAN_CAT_TYPE = "P";
}

这是我尝试实现修改的方式:

@MappedSuperclass
public class Animal {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", updatable = false, nullable = false)
    private Long id;
}

@MappedSuperclass
public abstract class Pet extends Animal {
    @ElementCollection(fetch = FetchType.EAGER)
    @MapKeyColumn(name = "name")
    @Column(name = "value")
    @CollectionTable(name = "pet_properties", joinColumns = @JoinColumn(name = "pet_id"))
    private Map<String, String> properties = new HashMap<>();
}

@Entity(name = "cats")
@Audited
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.CHAR)
@DiscriminatorValue(value = Cat.PET_TYPE)
public class Cat extends Pet {
    public static final String PET_TYPE = "C";
}

@Entity(name = "dogs")
@Audited
public class Dog extends Pet {
}

@Audited
@Entity(name = "persiancats")
@DiscriminatorValue(value = PersianCat.PERSIAN_CAT_TYPE)
public class PersianCat extends Pet {
    public static final String PERSIAN_CAT_TYPE = "P";
}

Hibernate创建pet_properties表,但它只引用dogscats。我的目的是为狗和猫(和persiancat)属性创建一个公共表

我错过了什么或做错了什么?

2 个答案:

答案 0 :(得分:1)

我猜想您想达到的目的在逻辑上是不可能的,这就是原因(我偶然发现了相同的问题,尽管在另一个领域)。为了从您的pet_properties表中引用一个表,Hibernate创建一个从pet_properties到目标表的外键(在您的情况下是狗还是猫)。外键本质上意味着该表中的每个条目都应对应于另一个表中的一个条目,而另一个表仅仅是一个表。因此,如果您说您的pet_properties条目同时引用了dogscats表,那么它将立即中断外键属性,因为如果引用了dogs,那么它将不引用猫,反之亦然。

因此,Hibernate为您提供的自动生成的选项(分别使用表dogs_propertiescats_properties)似乎是正确的方法。

答案 1 :(得分:0)

在删除此@CollectionTable(name = "cat_properties", joinColumns = @JoinColumn(name = "cat_id"))行后,Hibernate创建了两个表,一个名为cats_properties(用于猫和persiancats),另一个名为dogs_properties。这不完全是我想要的,这是两个实体的共同表,但它是可以接受的。