获得具有持久List类型字段的实体的最聪明的方法是什么?

Command.java

package persistlistofstring;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Persistence;

@Entity
public class Command implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long id;
    @Basic
    List<String> arguments = new ArrayList<String>();

    public static void main(String[] args) {
        Command command = new Command();

        EntityManager em = Persistence
                .createEntityManagerFactory("pu")
                .createEntityManager();
        em.getTransaction().begin();
        em.persist(command);
        em.getTransaction().commit();
        em.close();

        System.out.println("Persisted with id=" + command.id);
    }
}

这段代码产生:

> Exception in thread "main" javax.persistence.PersistenceException: No Persistence provider for EntityManager named pu: Provider named oracle.toplink.essentials.PersistenceProvider threw unexpected exception at create EntityManagerFactory: 
> oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException
> Local Exception Stack: 
> Exception [TOPLINK-30005] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException
> Exception Description: An exception was thrown while searching for persistence archives with ClassLoader: sun.misc.Launcher$AppClassLoader@11b86e7
> Internal Exception: javax.persistence.PersistenceException: Exception [TOPLINK-28018] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.EntityManagerSetupException
> Exception Description: predeploy for PersistenceUnit [pu] failed.
> Internal Exception: Exception [TOPLINK-7155] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.ValidationException
> Exception Description: The type [interface java.util.List] for the attribute [arguments] on the entity class [class persistlistofstring.Command] is not a valid type for a serialized mapping. The attribute type must implement the Serializable interface.
>         at oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException.exceptionSearchingForPersistenceResources(PersistenceUnitLoadingException.java:143)
>         at oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider.createEntityManagerFactory(EntityManagerFactoryProvider.java:169)
>         at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:110)
>         at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:83)
>         at persistlistofstring.Command.main(Command.java:30)
> Caused by: 
> ...

当前回答

根据Java持久化与Hibernate

用注释映射值类型集合[…]。在撰写本文时,它还不是Java持久性标准的一部分

如果你正在使用Hibernate,你可以这样做:

@CollectionOfElements(targetElement = String.class)
@JoinTable(name = "foo", joinColumns = @JoinColumn(name = "foo_id"))
@IndexColumn(name = "POSITION", base = 1)
@Column(name = "baz", nullable = false)
private List<String> arguments = new ArrayList<String>();

更新:注意,这个功能现在在JPA2中可用。

其他回答

Thiago的答案是正确的,添加了更具体的示例问题,@ElementCollection将在您的数据库中创建新表,但没有映射两个表,这意味着集合不是实体的集合,而是简单类型的集合(字符串等)或可嵌入元素的集合(类注释@Embeddable)。

下面是持久化String列表的示例

@ElementCollection
private Collection<String> options = new ArrayList<String>();

下面是持久化自定义对象列表的示例

@Embedded
@ElementCollection
private Collection<Car> carList = new ArrayList<Car>();

在这种情况下,我们需要使类Embeddable

@Embeddable
public class Car {
}

好吧,我知道有点晚了。但对于那些勇敢的灵魂来说,随着时间的推移,他们会看到这一点。

如文件中所写:

@Basic: 到数据库列的最简单的映射类型。基本注释可以应用于以下类型中的任意一种的持久属性或实例变量:]、枚举和任何其他实现java.io.Serializable的类型。

重要的部分是实现Serializable的类型

所以到目前为止,最简单和最容易使用的解决方案是简单地使用ArrayList而不是List(或任何可序列化的容器):

@Basic
ArrayList<Color> lovedColors;

@Basic
ArrayList<String> catNames;

但是请记住,这将使用系统序列化,因此它将带来一些代价,例如:

如果序列化对象模型将改变,你可能无法恢复数据 存储的每个元素都会增加少量开销。

简而言之

存储标志或少数元素非常简单,但我不这么做 建议它存储可能变大的数据。

我也遇到了同样的问题,所以我投资了可能的解决方案,但最后我决定实现我的“;”分离的字符串列表。

所以我有

// a ; separated list of arguments
String arguments;

public List<String> getArguments() {
    return Arrays.asList(arguments.split(";"));
}

这样,列表在数据库表中很容易阅读/编辑;

根据Java持久化与Hibernate

用注释映射值类型集合[…]。在撰写本文时,它还不是Java持久性标准的一部分

如果你正在使用Hibernate,你可以这样做:

@CollectionOfElements(targetElement = String.class)
@JoinTable(name = "foo", joinColumns = @JoinColumn(name = "foo_id"))
@IndexColumn(name = "POSITION", base = 1)
@Column(name = "baz", nullable = false)
private List<String> arguments = new ArrayList<String>();

更新:注意,这个功能现在在JPA2中可用。

这个答案是在JPA2之前实现的,如果你正在使用JPA2,请参阅上面的ElementCollection答案:

模型对象内的对象列表通常被认为是与另一个对象的“OneToMany”关系。但是,String本身并不是一对多关系的允许客户端,因为它没有ID。

因此,您应该将字符串列表转换为包含ID和String的参数类JPA对象列表。您可以潜在地使用String作为ID,这将在您的表中节省一点空间,既可以删除ID字段,也可以合并字符串相等的行,但您将失去将参数按原始顺序排序的能力(因为您没有存储任何排序信息)。

Alternatively, you could convert your list to @Transient and add another field (argStorage) to your class that is either a VARCHAR() or a CLOB. You'll then need to add 3 functions: 2 of them are the same and should convert your list of Strings into a single String (in argStorage) delimited in a fashion that you can easily separate them. Annotate these two functions (that each do the same thing) with @PrePersist and @PreUpdate. Finally, add the third function that splits the argStorage into the list of Strings again and annotate it @PostLoad. This will keep your CLOB updated with the strings whenever you go to store the Command, and keep the argStorage field updated before you store it to the DB.

我还是建议做第一种情况。这对以后的恋爱很有帮助。