如何在JPA中映射自定义集合?

Den*_*nis 9 java collections persistence hibernate jpa

我在使用JPA(Hiberante提供程序)映射自定义集合时遇到问题.例如,当我使用带属性的对象时

List<Match> matches;
Run Code Online (Sandbox Code Playgroud)

<one-to-many name="matches">
    <cascade>
        <cascade-all />
    </cascade>
</one-to-many>
Run Code Online (Sandbox Code Playgroud)

在我的ORM文件中,它没关系; 但是,如果我替换"列出匹配;" 通过

private Matches matches;
Run Code Online (Sandbox Code Playgroud)

,其中"匹配"定义如下:

public class Matches extends ArrayList<Match> {

    private static final long serialVersionUID = 1L;
}
Run Code Online (Sandbox Code Playgroud)

它产生以下错误:

Caused by: org.hibernate.AnnotationException: Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: by.sokol.labs.jpa.MatchBox.matches
Run Code Online (Sandbox Code Playgroud)

感谢您的关注!

Boz*_*zho 7

您可以,但您必须将其称为常见集合之一 - ListSet.

所以:

private List matches = new Matches();
Run Code Online (Sandbox Code Playgroud)

为什么?例如,因为Hibernate会为您的集合创建代理以启用延迟加载.所以它创建PersistentList,PersistentSetPersistentBag,这是List但不是Matches.所以,如果你想为该集合添加其他方法 - 嗯,你不能.

查看此文章了解更多详细信息.

但是,你有一个解决方案.不要使用继承,使用组合.例如,您可以向您的实体添加一个方法getMatchesCollection()(除了传统的getter之外),它看起来像:

 public Matches getMatchesCollection() {
    return new Matches(matches);
 }
Run Code Online (Sandbox Code Playgroud)

你的Matches课程看起来像(使用google-collections ' ForwardingList):

public class Matches extends ForwardingList {
    private List<Match> matches;
    public Matches(List<Match> matches) { this.matches = matches; }
    public List<Match> delegate() { return matches; }
    // define your additional methods
}
Run Code Online (Sandbox Code Playgroud)

如果你不能使用google集合,只需定义ForwardingList你自己 - 它调用底层的所有方法List

如果您不需要任何其他方法来操作结构,则不要定义自定义集合.


Pas*_*ent 5

Hibernate 要求将持久集合值字段声明为接口类型(因为出于延迟加载的目的,它们将被 Hibernate 的实现替换)。来自参考文档:

6.1. 持久集合

Hibernate 要求将持久集合值字段声明为接口类型。例如:

public class Product {
    private String serialNumber;
    private Set parts = new HashSet();

    public Set getParts() { return parts; }
    void setParts(Set parts) { this.parts = parts; }
    public String getSerialNumber() { return serialNumber; }
    void setSerialNumber(String sn) { serialNumber = sn; }
}
Run Code Online (Sandbox Code Playgroud)

实际的接口可能是 java.util.Setjava.util.Collectionjava.util.Listjava.util.Map、 或您喜欢的任何内容(“java.util.SortedSetjava.util.SortedMap喜欢的任何内容”意味着您必须编写 的实现 org.hibernate.usertype.UserCollectionType。)

注意实例变量是如何用 的实例初始化的 HashSet。这是初始化新实例化(非持久)实例的集合值属性的最佳方法。当您使实例持久化时,persist()例如通过调用,Hibernate 实际上会将 替换 HashSet为 Hibernate 自己实现的实例Set

所以你的第二种方法是不可能的,至少不是你声明的方式。但说实话,我真的不明白这一点。