@ElementCollection Java持久性(Hibernate)导致加载重复实例

时间:2011-07-19 18:46:38

标签: java hibernate annotations persistence

使用@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调用。

3 个答案:

答案 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。

相关问题