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

发布于 2024-09-08 03:14:56 字数 797 浏览 2 评论 0原文

我在使用 JPA(Hiberante 提供程序)映射自定义集合时遇到问题。例如,当我

List<Match> matches;

使用带有

<one-to-many name="matches">
    <cascade>
        <cascade-all />
    </cascade>
</one-to-many>

在 ORM 文件中 属性的对象时,这是可以的;但是,如果我将 "List matches;" 替换为

private Matches matches;

,其中 "Matches" 的定义如下:

public class Matches extends ArrayList<Match> {

    private static final long serialVersionUID = 1L;
}

它会产生以下错误:

Caused by: org.hibernate.AnnotationException: Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: by.sokol.labs.jpa.MatchBox.matches

感谢您的关注!

I have problems in mapping custom collection with JPA (Hiberante provider). For example when I am using object with attribute

List<Match> matches;

with

<one-to-many name="matches">
    <cascade>
        <cascade-all />
    </cascade>
</one-to-many>

in my ORM file, it is allright; But if I replace "List matches;" by

private Matches matches;

,where "Matches" is defined like:

public class Matches extends ArrayList<Match> {

    private static final long serialVersionUID = 1L;
}

It produces following error:

Caused by: org.hibernate.AnnotationException: Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: by.sokol.labs.jpa.MatchBox.matches

Thanks for your attention!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

↘人皮目录ツ 2024-09-15 03:14:56

可以,但必须将其作为常见集合之一进行引用 - ListSet

所以:

private List matches = new Matches();

为什么?例如,因为 Hibernate 为您的集合创建代理以启用延迟加载。因此它创建了 PersistentListPersistentSetPersistentBag,它们是 List 但不是 Matches.因此,如果您想向该集合添加其他方法 - 嗯,您不能。

查看这篇文章了解更多详细信息。

不过,你有一个解决方案。不要使用继承,而使用组合。例如,您可以向实体添加一个名为 getMatchesCollection() 的方法(除了传统的 getter 之外),该方法如下所示:

 public Matches getMatchesCollection() {
    return new Matches(matches);
 }

您的 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
}

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

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

You can, but you have to refer to it as one of the common collections - List or Set.

so:

private List matches = new Matches();

Why? Because Hibernate makes proxies to your collections to enable lazy loading, for example. So it creates PersistentList, PersistentSet and PersistentBag, which are List but aren't Matches. So, if you want to add additional methods to that collection - well, you can't.

Check this article for more details.

You have a solution, however. Don't use inheritance, use composition. You can, for example, add a method to your entity called getMatchesCollection() (in addition to the traditional getter), which looks like:

 public Matches getMatchesCollection() {
    return new Matches(matches);
 }

And your Matches class would look like (using 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
}

If you can't use google collections, simply define the ForwardingList yourself - it's calling all the methods of the underlying List

If you don't need any additional methods to operate on the structure, then don't define a custom collection.

抱猫软卧 2024-09-15 03:14:56

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

6.1。持久集合

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

公共类产品{
    私有字符串序列号;
    私有 Set 部分 = new HashSet();

    public Set getParts() { 返回零件; }
    void setParts(设置零件) { this.parts = parts; }
    公共字符串 getSerialNumber() { 返回序列号; }
    void setSerialNumber(String sn) { 序列号 = sn; }
}

实际的界面可能是
java.util.Setjava.util.Collection
java.util.Listjava.util.Map
java.util.SortedSet,
java.util.SortedMap 或任何你
就像(“任何你喜欢的东西”意味着你
必须编写一个实现

org.hibernate.usertype.UserCollectionType。)

注意实例变量是如何的
用实例初始化
哈希集。这是最好的方法
初始化集合值
新实例化的属性
(非持久)实例。当你
使实例持久化,通过
例如调用persist(),
Hibernate 实际上将取代
HashSet 具有以下实例
Hibernate 自己的 Set 实现。

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

Hibernate requires persistent collection-valued fields to be declared as an interface type (because they will be replaced with Hibernate's implementation for lazy loading purposes). From the reference documentation:

6.1. Persistent collections

Hibernate requires that persistent collection-valued fields be declared as an interface type. For example:

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; }
}

The actual interface might be
java.util.Set, java.util.Collection,
java.util.List, java.util.Map,
java.util.SortedSet,
java.util.SortedMap or anything you
like ("anything you like" means you
will have to write an implementation
of
org.hibernate.usertype.UserCollectionType.)

Notice how the instance variable was
initialized with an instance of
HashSet. This is the best way to
initialize collection valued
properties of newly instantiated
(non-persistent) instances. When you
make the instance persistent, by
calling persist() for example,
Hibernate will actually replace the
HashSet with an instance of
Hibernate's own implementation of Set.

So your second approach is not possible, at least not the way you declared it. But to be honest, I don't really see the point.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文