当您已经知道父实体的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;
...希望它不会发出数据库查询,但显然会:(
答案 0 :(得分:1)
在查询中使用select new MyEntity(...)
意味着您将MyEntity用作DTO:包含实际MyEntity实例的某些字段的分离对象。
如果您希望它引用一个懒惰的子集合,只需使用select e from MyEntity e ...
:您将获得一个附加的MyEntity实例及其懒惰(未初始化)的子集合。只要调用子集合的任何方法,就会执行另一个查询来加载此集合。
如果您坚持想要使用分离的MyEntity,并且想要引用其子列表,那么您确实必须重新加载实体(从而获得其附加版本),这当然会触发一个额外的SQL查询,只是为了再次使用其所有字段来填充实体。
我会避免将MyEntity类用作DTO,而是使用专用类,而不包含子列表。因此,调用者代码将清楚地知道需要执行额外的临时HQL查询来获取子列表。