在没有数据库调用的情况下获取延迟的PersistentCollection

时间:2011-09-14 11:32:45

标签: java hibernate persistence lazy-loading

当您已经知道父实体的ID并且您也知道该实体实际存在于数据库中时,是否有办法获取实体的Collection属性,而不触发数据库查询

获取此类集合的最简单方法当然是使用EntityManager.find(),但它会产生不必要的数据库查询:

    MyEntity entity = em.find(MyEntity.class, id); // prints "select ... from MyEntity"
    Collection c = entity.getSomeChildren();

我曾假设EntityManager.getReference()可以解决这个问题,但不幸的是,即使getReference(),在调用entity.getSomeChildren()时也会查询数据库,尽管它是FetchType.LAZY属性:< / p>

    MyEntity entity = em.getReference(MyEntity.class, id);
    Collection c = entity.getSomeChildren();       // prints "select ... from MyEntity"

幸运的是,它不会发出"select ... from MyEntity_SomeChildren"查询,除非我实际上在c上调用某个方法,并且我理解最后一个效果正是因为FetchType.LAZY注释。但我认为即使是第一个查询也是多余的。

以下是MyEntity

的代码
@Entity
public class MyEntity {
    private String id;
    private Collection<SomeChildren> someChildren;

    @Id
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @OneToMany(fetch = FetchType.LAZY)
    public Collection<SomeChildren> getSomeChildren() {
        return someChildren;
    }

    public void setSomeChildren(Collection<SomeChildren> someCollection) {
        this.someChildren = someCollection;
    }
}

更新:我为什么需要这个? 完整的方案是这样的:我有一个MyEntity实例,我从new运算符的查询中获得:

    @SuppressWarnings({"unchecked"})
    List<MyEntity> list = em.createQuery("select new MyEntity(...) from MyEntity e where ...").getResultList();
    MyEntity original = list.get(0);
    return  original;

这很好用,但有时候(只有有时)我需要entity.getSomeChildren()。因此我不想将它传递给构造函数,所以我想到了这个技巧:

    MyEntity original = list.get(0);
    MyEntity entity = em.getReference(MyEntity.class, original.getId());
    Collection c = entity.getSomeChildren(); // prints "select ... from MyEntity where id=?"
    original.setSomeChildren(c);
    return  original;

...希望它不会发出数据库查询,但显然会:(

1 个答案:

答案 0 :(得分:1)

在查询中使用select new MyEntity(...)意味着您将MyEntity用作DTO:包含实际MyEntity实例的某些字段的分离对象。

如果您希望它引用一个懒惰的子集合,只需使用select e from MyEntity e ...:您将获得一个附加的MyEntity实例及其懒惰(未初始化)的子集合。只要调用子集合的任何方法,就会执行另一个查询来加载此集合。

如果您坚持想要使用分离的MyEntity,并且想要引用其子列表,那么您确实必须重新加载实体(从而获得其附加版本),这当然会触发一个额外的SQL查询,只是为了再次使用其所有字段来填充实体。

我会避免将MyEntity类用作DTO,而是使用专用类,而不包含子列表。因此,调用者代码将清楚地知道需要执行额外的临时HQL查询来获取子列表。