使用@ElementCollection时,load all正在加载一个对象的多个实例。更具体地说,它为collectionOfStrings中的每个元素加载一个实例。
例如,具有单个MyClass实例且具有collectionOfStrings.size()== 4的数据库,加载所有MyClass值的调用将返回大小为4的List(所有相同的对象),而不是仅返回1个对象。
是否有一种干净简单的方法来解决这个问题,还是预期的行为?
// Parent class is a @MappedSuperclass which may or may not be relevant to the issue
@Entity
public class MyClass extends ParentClass {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@ElementCollection(fetch=FetchType.EAGER)
@IndexColumn(name="indexColumn")
private List<String> collectionOfStrings;
// other instance variables, constructors, getters, setters, toString, hashcode and equals
}
public class MyClassDAO_Hibernate extends GenericHibernateDAO<MyClass, Long> implements MyClassDAO {
@Override
public List<MyClass> loadAll() {
List<MyClass> entityList = null;
Session session = getSession();
Transaction trans = session.beginTransaction();
entityList = findByCriteria(session);
trans.commit();
return entityList;
}
}
protected List<T> findByCriteria(Session session, Criterion... criterion) {
Criteria crit = session.createCriteria(getPersistentClass());
for (Criterion c : criterion) {
crit.add(c);
}
return crit.list();
}
MyClassDAO myClassDAO = new MyClassDAO_Hibernate(); // in reality, implementation type is determined with a Factory
...
List<MyClass> myClassInstances = myClassDAO.loadAll();
谢谢, HeavyE
编辑:添加了findByCriteria调用。
答案 0 :(得分:8)
我不确定它是否是错误或合法行为,但可以通过应用DISTINCT_ROOT_ENTITY
结果转换器来修复:
protected List<T> findByCriteria(Session session, Criterion... criterion) {
Criteria crit = session.createCriteria(getPersistentClass());
for (Criterion c : criterion) {
crit.add(c);
}
crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
return crit.list();
}
答案 1 :(得分:3)
只有在急切地提取集合时才会观察到这种情况。 Hibernate将此注释映射转换为外部联接查询,这会在每个链接的collectionOfString元素的根元素列表中生成多个。
请参阅Hibernate ORM问题跟踪器中的故障HHH-6783以了解此确切问题。而且显然没有解决方案。 : - (
此处还提供了与外部联接有关的链接to the Hibernate FAQ。
我正在处理完全相同的问题。在我的案例中使用@ElementCollection是有意义的,但不是以审查我的所有数据访问层实现为代价。 什么是做什么?
答案 2 :(得分:2)
这是List的正确行为。 列表允许重复对象,这就是您需要索引列的原因。
这是一般的集合类型,可以通过Hibernate进行映射:
设置是一个不会多次出现任何项目的集合。根据我的经验,这是最常见的持久性集合类型。
Bag 是一个集合,其中的项目可能不止一次出现:它们的效率非常低,因为hibernate无法判断您放入其中的项目是否与其中的项目相同(假设它们是等于),所以它必须删除整个集合并从内存中重新保存。
列表是一个索引包。索引让hibernate知道特定的内存中对象是否与相同的on-DB对象相同,因此不需要完全删除/重新插入。
Map 就像一个列表,除了索引不必是可计算的(通常是顺序的)整数,它可以是任何东西,甚至是另一个对象。
因此,在您的情况下,我建议您使用Set。