获得具有List类型字段的实体的最智能方法是什么?
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 Listarguments = new ArrayList (); 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: > ...
小智.. 187
使用一些JPA 2实现:它增加了一个@ElementCollection注释,类似于Hibernate的一个,这不正是你需要的.有一个例子在这里.
编辑
正如下面的评论中所提到的,正确的JPA 2实现是
javax.persistence.ElementCollection @ElementCollection Mapcollection;
请参阅:http://docs.oracle.com/javaee/6/api/javax/persistence/ElementCollection.html
使用一些JPA 2实现:它增加了一个@ElementCollection注释,类似于Hibernate的一个,这不正是你需要的.有一个例子在这里.
编辑
正如下面的评论中所提到的,正确的JPA 2实现是
javax.persistence.ElementCollection @ElementCollection Mapcollection;
请参阅:http://docs.oracle.com/javaee/6/api/javax/persistence/ElementCollection.html
这个答案是在JPA2之前的实现中做出的,如果您使用的是JPA2,请参阅上面的ElementCollection答案:
模型对象内的对象列表通常被视为与另一个对象的"OneToMany"关系.但是,String不是(本身)一对多关系的允许客户端,因为它没有ID.
因此,您应该将您的Strings列表转换为包含ID和String的Argument-class JPA对象列表.您可以使用String作为ID,这样可以节省表中的一小部分空间,既可以删除ID字段,又可以合并字符串相等的行,但是您将失去将参数重新排序为原始顺序的能力(因为您没有存储任何订购信息).
或者,您可以将列表转换为@Transient,并将另一个字段(argStorage)添加到您的类中,该类是VARCHAR()或CLOB.然后,您需要添加3个函数:其中2个是相同的,并且应该将您的字符串列表转换为单个字符串(在argStorage中),以一种您可以轻松分隔它们的方式分隔.使用@PrePersist和@PreUpdate注释这两个函数(每个函数都做同样的事情).最后,添加第三个函数,将argStorage再次拆分为字符串列表,并将其注释为@PostLoad.每当您存储命令时,这将使您的CLOB更新为字符串,并在将argStorage字段存储到数据库之前保持更新.
我仍然建议做第一个案例.以后这是真正的关系的好习惯.
很抱歉重振旧线程,但是任何人都应该寻找替代解决方案,将字符串列表存储为数据库中的一个字段,以下是我如何解决这个问题.像这样创建一个转换器:
import java.util.Arrays; import java.util.List; import javax.persistence.AttributeConverter; import javax.persistence.Converter; @Converter public class StringListConverter implements AttributeConverter, String> { private static final String SPLIT_CHAR = ";"; @Override public String convertToDatabaseColumn(List
stringList) { return String.join(SPLIT_CHAR, stringList); } @Override public List convertToEntityAttribute(String string) { return Arrays.asList(string.split(SPLIT_CHAR)); } }
现在在您的实体上使用它,如下所示:
@Convert(converter = StringListConverter.class) private ListyourList;
在数据库中,您的列表将存储为foo; bar; foobar,在Java对象中,您将获得包含这些字符串的列表.
希望这对某人有帮助.
根据Java Persistence with Hibernate
使用注释[...]映射值类型的集合.在撰写本文时,它不是Java Persistence标准的一部分
如果你使用的是Hibernate,你可以这样做:
@org.hibernate.annotations.CollectionOfElements( targetElement = java.lang.String.class ) @JoinTable( name = "foo", joinColumns = @JoinColumn(name = "foo_id") ) @org.hibernate.annotations.IndexColumn( name = "POSITION", base = 1 ) @Column(name = "baz", nullable = false) private Listarguments = new ArrayList ();
更新:请注意,现在可以在JPA2中使用.
我们也可以用这个.
@Column(name="arguments") @ElementCollection(targetClass=String.class) private Listarguments;
当使用JPA的Hibernate实现时,我发现简单地将类型声明为ArrayList而不是List允许hibernate存储数据列表.
显然,与创建实体对象列表相比,这有许多缺点.没有延迟加载,没有能力从其他对象引用列表中的实体,可能在构造数据库查询时更加困难.但是当你处理相当原始类型的列表时,你总是希望与实体一起急切地获取,那么这种方法对我来说似乎很好.
@Entity public class Command implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) Long id; ArrayListarguments = new ArrayList (); }
我有同样的问题,所以我投入了可能的解决方案,但最后我决定实施我的';' 分隔的String列表.
所以我有
// a ; separated list of arguments String arguments; public ListgetArguments() { return Arrays.asList(arguments.split(";")); }
这样,列表在数据库表中很容易读/可编辑;
好吧,我知道它有点晚了.但是对于那些勇敢的灵魂来说,随着时间的推移,这将成为现实.
如文档中所述:
@Basic:最简单的映射到数据库列的类型.Basic注释可以应用于以下任何类型的持久属性或实例变量:Java原始类型,[...],枚举以及实现java.io.Serializable的任何其他类型.
重要的部分是实现Serializable的类型
到目前为止,最简单易用的解决方案是使用ArrayList而不是List(或任何可序列化的容器):
@Basic ArrayListlovedColors; @Basic ArrayList catNames;
但请记住,这将使用系统序列化,因此它会带来一些代价,例如:
如果序列化对象模型将更改,则可能无法还原数据
为存储的每个元素添加小开销.
简而言之
存储标志或少量元素非常简单,但我不会建议它存储可能变大的数据.