【问题标题】:use entitymanager to load collections eagerly使用 entitymanager 急切地加载集合
【发布时间】:2012-08-31 13:39:27
【问题描述】:

我有一个实体(联系人),它有一个延迟加载的集合。我不知道要更改它,但我需要在执行 em.find(Contact.class, myID) 时加载集合,这可以在不更改实体且不使用 jpql 语句和 fetch 的情况下完成。 ?

public class Contact implements Serializable{

    private static final long serialVersionUID = 1L;

    @Id 
    @Column(name="contactId", nullable=false)
    public String contactId;    

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "contact", orphanRemoval = true, fetch=FetchType.LAZY)
    private List<ContactTaskRelation> taskRelations = new ArrayList<ContactTaskRelation>();

}

来自我的无状态 bean

@PersistenceContext(unitName="myContext")
private EntityManager em;

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
private Contact getContact(ContactMapping mappedContact){
    //force em to load the collection of taskRelations
    return em.find(Contact .class, mappedContact.getContact());
}

【问题讨论】:

    标签: java ejb entitymanager


    【解决方案1】:
    Contact entity = em.find(Contact.class, mappedContact.getContact());
    entity.getTaskRelations().size(); // this will fetch the TaskRelations
    return entity;
    

    缺点是这会对数据库进行两次查询:一个获取联系人,另一个获取 TaskRelations。

    另一种选择是进行查询,如下所示:

    String queryString = "SELECT model FORM Contact model JOIN FETCH model.taskRelations WHERE model.id = :id";
    Query query = em.createQuery(queryString);
    query.setParameter("id", mappedContact.getContact());
    return query.getSingleResult(); // or getResultList();
    

    此选项只进行一次查询。

    【讨论】:

    • 是的,我考虑您的第一个选项,但这要求我知道所有集合,并且将来会向实体添加更多集合,因此我也必须在我的 bean 方法中进行更新。所以我真的不能接受。第二个会有同样的问题,实际上我有很多带有集合的实体,这只是一个简化的例子。感谢您的尝试 =)
    【解决方案2】:

    您可以结合@arthuro 的解决方案和反射来调用所有getter。像这样的:

    public static <T> T findEager(EntityManager em, Class<T> type, Object id) {
        T entity = em.find(type, id);
        for (Field field: type.getDeclaredFields()) {
            OneToMany annotation = field.getAnnotation(OneToMany.class);
            if (annotation != null) {
                if (annotation.fetch().equals(FetchType.LAZY)) {
                    try {
                        new PropertyDescriptor(field.getName(), type).getReadMethod().invoke(entity);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return entity;
    }
    

    然后像这样调用它:

    Contact entity = findEager(em, Contact.class, mappedContact.getContact());
    

    【讨论】:

    • 请记住,这可能会产生大量查询,因此可能是性能问题。
    猜你喜欢
    • 2013-07-28
    • 1970-01-01
    • 2010-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多