使用@OrderColumn 和派生实体在 JPA 中加入子类策略

Joined Subclass strategy in JPA with @OrderColumn and derived entities

我正在尝试使用联合子类策略实现继承,同时跟踪组合实体列表的顺序。

我有一个 SHOP table,有一个 ID 和一些元数据。

SHOP 必须维护一个有序列表,其中包含多种类型的实体,这些实体具有一些共同的元数据。

这是我目前在实体和映射方面的情况:

@Entity
public class Shop extends PersistedEntity {

    // Persistend entity is a common class that declares the @Id column as:
    // @Id
    // @GeneratedValue(strategy = GenerationType.AUTO)
    // public int getId() {
    //  return this.id;
    // }

    // ... some generic fields

    private List<ShopAssets> shopAssets = new ArrayList<ShopAssets>();

    @ManyToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
    @JoinTable(name = "ShopAssets", joinColumns = { @JoinColumn(name = "shop_id") }, inverseJoinColumns = { @JoinColumn(name = "id") })
    @OrderColumn(name="position")
    public List<ShopAssets> getShopAssets() {
        return shopAssets;
    }
}


@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(discriminatorType = DiscriminatorType.STRING, name = "assetType")
public class ShopAsset extends PersistedEntity {

    // Again, the id integer column is inherited from PersistedEntity

    private Shop shop;
    private int position;
    private ShopFieldAsset keyAsset;

    @ManyToOne
    @JoinColumn(name = "shop_id")
    public Shop getShop() {
        return shop;
    }

    public int getPosition() {
        return position;
    }

    @ManyToOne
    @JoinColumn(name = "keyAsset_id")
    public ShopFieldAsset getKeyAsset() {
        return keyAsset;
    }

    // ... setters not included
}


@Entity
@DiscriminatorValue("field")
@PrimaryKeyJoinColumn(name = "id")
public class ShopFieldAsset extends ShopAsset {

    // ... bunch of standard string properties

}

@Entity
@DiscriminatorValue("common")
@PrimaryKeyJoinColumn(name = "id")
public class ShopCommonAsset extends ShopAsset {

    // ... bunch of standard string properties

}

@Entity
@DiscriminatorValue("expired")
@PrimaryKeyJoinColumn(name = "id")
public class ShopExpiredAsset extends ShopAsset {

    // ... bunch of standard string properties

}

数据库table如下(粗略):

Shop: id(PK). name, location
ShopAsset: id(PK), shop_id, assetType, position, keyAsset_id(FK on ShopFieldAsset[id])
ShopFieldAsset: id(PK and also FK to ShopAsset[id]), name, type, other standard columns);
ShopCommonAsset: id(PK and also FK to ShopAsset[id]), name, type, other standard columns);
ShopExpiredAsset: id(PK and also FK to ShopAsset[id]), name, type, other standard columns);

我在测试中试图做的就是创建一个商店并使用资产集合来保存它,维护它们添加到商店的顺序。

我得到的是:

org.hibernate.MappingException: Foreign key (FK_ep3g3p25oddon8apvq8kgji6w:ShopFieldAsset [id])) must have same number of columns as the referenced primary key (ShopAsset [shop_id,position])

而且我只是不明白主键定义的来源...

我意识到派生实体可能会妨碍(事实是任何 ShopAsset 在 ShopFieldAsset 子类上都有一个外键...),但我不知道应该如何定义映射。

好像这还不够,if/when 我让它工作了,有没有一种聪明的方法可以让 Shop 上的 getter 检索特定类型的资产集合,例如getShopCommonAssets() ?我简要地研究了使用@Where,但很明显我把它放在一边,直到我掌握了基础知识!

非常感谢任何帮助。

睡个好觉真是太神奇了。

我解决了大部分问题:

  1. 通过删除父 Shop 实体上的 @JoinTable 注释。看起来这就是在尝试添加 ShopAsset 时混淆插入语句的原因。

  2. 通过改变 subclasses 得到这个:

    @PrimaryKeyJoinColumn(name = "id", referencedColumnName = "id")

而不只是

@PrimaryKeyJoinColumn(name = "id")

东西现在看起来很开心,甚至 @OrderColumn 工作正常。

我找到了一个答案来帮助我解决问题的最后一部分:

How to map collection of each subclass from same hierarchy onto one owning class?

但是当我尝试这样做时:

@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER, mappedBy = "shop", targetEntity = TornadoLabel.class)
public List<ShopCommonAssets> getShopCommonAssets() {
    return shopCommonAssets;
}

我得到

org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: com.shopping.ShopCommonAsset.shop in com.shopping.Shop.shopCommonAssets

我猜这是因为我的 'shop' 属性 在父级 class 上,与我链接到的答案中的示例不同。