2010-05-29 73 views
5

我无法优化Hibernate查询以避免执行连接或次级选择。避免使用Hibernate Criteria或HQL查询进行二级选择或连接

当执行(标准或HQL),如下面的一个Hibernate查询:

return getSession().createQuery(("from GiftCard as card where card.recipientNotificationRequested=1").list(); 

...和where子句检查不需要任何与其他表中的连接属性...但Hibernate仍然执行与其他表的完全连接(或根据我如何设置fetchMode进行二级选择)。

有问题的对象(GiftCard)有一对ManyToOne关联,我宁愿在这种情况下(但不一定是所有情况下)都懒惰地加载。我想要一个解决方案,可以控制执行查询时延迟加载的内容。

这里的礼金券实体是什么样子:

@Entity 
@Table(name = "giftCards") 
public class GiftCard implements Serializable 
{ 
private static final long serialVersionUID = 1L; 

private String id_; 
private User buyer_; 
private boolean isRecipientNotificationRequested_; 


@Id 
public String getId() 
{ 
    return this.id_; 
} 

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

@ManyToOne 
@JoinColumn(name = "buyerUserId") 
@NotFound(action = NotFoundAction.IGNORE) 
public User getBuyer() 
{ 
    return this.buyer_; 
} 
public void setBuyer(User buyer) 
{ 
    this.buyer_ = buyer; 
} 

@Column(name="isRecipientNotificationRequested", nullable=false, columnDefinition="tinyint") 
public boolean isRecipientNotificationRequested() 
{ 
    return this.isRecipientNotificationRequested_; 
} 

public void setRecipientNotificationRequested(boolean isRecipientNotificationRequested) 
{ 
    this.isRecipientNotificationRequested_ = isRecipientNotificationRequested; 
} 
} 

回答

2

至于说

我想要我可以控制什么是延迟加载当我执行查询

如果你有这样一个

@Entity 
public class GiftCard implements Serializable { 

    private User buyer; 

    @ManyToOne 
    @JoinColumn(name="buyerUserId") 
    public User getBuyer() { 
     return this.buyer; 
    } 
} 
的映射解决方案

任何* ToOne关系,例如@OneToOne和@ManyToOne,默认情况下是FetchType.EAGER,这意味着它将是一个抓住了。但是,这不可能是你想要的。你说什么我可以控制什么是懒惰加载可以翻译为提取策略POJO in Action书支持所以根据您的使用情况下,像这样的(注意方法签名)的模式

public class GiftCardRepositoryImpl implements GiftCardRepository { 

    public List<GiftCard> findGiftCardWithBuyer() { 
     return sessionFactory.getCurrentSession().createQuery("from GiftCard c inner join fetch c.buyer where c.recipientNotificationRequested = 1").list(); 
    } 

} 

,您可以创建自己的发现...与...和...方法。它会照顾取正是你想要的

但它有一个问题:它不支持通用的方法签名。对于每个@Entity存储库,您必须定义您的自定义找到... With ...和方法。正因为如此,我告诉你我是如何定义一个通用存储库

public interface Repository<INSTANCE_CLASS, UPDATABLE_INSTANCE_CLASS, PRIMARY_KEY_CLASS> { 

    void add(INSTANCE_CLASS instance); 
    void remove(PRIMARY_KEY_CLASS id); 
    void update(PRIMARY_KEY_CLASS id, UPDATABLE_INSTANCE_CLASS updatableInstance); 
    INSTANCE_CLASS findById(PRIMARY_KEY_CLASS id); 
    INSTANCE_CLASS findById(PRIMARY_KEY_CLASS id, FetchingStrategy fetchingStrategy); 
    List<INSTANCE_CLASS> findAll(); 
    List<INSTANCE_CLASS> findAll(FetchingStrategy fetchingStrategy); 
    List<INSTANCE_CLASS> findAll(int pageNumber, int pageSize); 
    List<INSTANCE_CLASS> findAll(int pageNumber, int pageSize, FetchingStrategy fetchingStrategy); 
    List<INSTANCE_CLASS> findAllByCriteria(Criteria criteria); 
    List<INSTANCE_CLASS> findAllByCriteria(Criteria criteria, FetchingStrategy fetchingStrategy); 
    List<INSTANCE_CLASS> findAllByCriteria(int pageNumber, int pageSize, Criteria criteria); 
    List<INSTANCE_CLASS> findAllByCriteria(int pageNumber, int pageSize, Criteria criteria, FetchingStrategy fetchingStrategy); 

} 

但是,有时,你不希望所有的由通用库接口中定义的方法。解决方案:创建一个AbstractRepository类,它将实现一个虚拟存储库。Spring框架,例如大量使用这种模式的接口>> AbstractInterface

public abstract class AbstractRepository<INSTANCE_CLASS, UPDATABLE_INSTANCE_CLASS, PRIMARY_KEY_CLASS> implements Repository<INSTANCE_CLASS, UPDATABLE_INSTANCE_CLASS, PRIMARY_KEY_CLASS> { 

    public void add(INSTANCE_CLASS instance) { 
     throw new UnsupportedOperationException("Not supported yet."); 
    } 

    public void remove(PRIMARY_KEY_CLASS id) { 
     throw new UnsupportedOperationException("Not supported yet."); 
    } 

    public void update(PRIMARY_KEY_CLASS id, UPDATABLE_INSTANCE_CLASS updatableInstance) { 
     throw new UnsupportedOperationException("Not supported yet."); 
    } 

    public INSTANCE_CLASS findById(PRIMARY_KEY_CLASS id) { 
     throw new UnsupportedOperationException("Not supported yet."); 
    } 

    public INSTANCE_CLASS findById(PRIMARY_KEY_CLASS id, FetchingStrategy fetchingStrategy) { 
     throw new UnsupportedOperationException("Not supported yet."); 
    } 

    public List<INSTANCE_CLASS> findAll() { 
     throw new UnsupportedOperationException("Not supported yet."); 
    } 

    public List<INSTANCE_CLASS> findAll(FetchingStrategy fetchingStrategy) { 
     throw new UnsupportedOperationException("Not supported yet."); 
    } 

    public List<INSTANCE_CLASS> findAll(int pageNumber, int pageSize) { 
     throw new UnsupportedOperationException("Not supported yet."); 
    } 

    public List<INSTANCE_CLASS> findAll(int pageNumber, int pageSize, FetchingStrategy fetchingStrategy) { 
     throw new UnsupportedOperationException("Not supported yet."); 
    } 

    public List<INSTANCE_CLASS> findAllByCriteria(Criteria criteria) { 
     throw new UnsupportedOperationException("Not supported yet."); 
    } 

    public List<INSTANCE_CLASS> findAllByCriteria(Criteria criteria, FetchingStrategy fetchingStrategy) { 
     throw new UnsupportedOperationException("Not supported yet."); 
    } 

    public List<INSTANCE_CLASS> findAllByCriteria(int pageNumber, int pageSize, Criteria criteria) { 
     throw new UnsupportedOperationException("Not supported yet."); 
    } 

    public List<INSTANCE_CLASS> findAllByCriteria(int pageNumber, int pageSize, Criteria criteria, FetchingStrategy fetchingStrategy) { 
     throw new UnsupportedOperationException("Not supported yet."); 
    } 

} 

所以你GiftCardRepository可以重新写为(见延伸,而不是工具)和只覆盖你真正想要的

public class GiftCardRepository extends AbstractRepository<GiftCard, GiftCard, String> { 

    public static final GIFT_CARDS_WITH_BUYER GIFT_CARDS_WITH_BUYER = new GIFT_CARDS_WITH_WITH_BUYER(); 
    public static final GIFT_CARDS_WITHOUT_NO_RELATIONSHIP GIFT_CARDS_WITHOUT_NO_RELATIONSHIP = new GIFT_CARDS_WITHOUT_NO_RELATIONSHIP(); 

    public List<GiftCard> findAll(FetchingStrategy fetchingStrategy) { 
     sessionFactory.getCurrentSession().getNamedQuery(fetchingStrategy.toString()).list(); 
    } 


    /** 
     * FetchingStrategy is just a marker interface 
     * public interface FetchingStrategy {} 
     * 
     * And AbstractFetchingStrategy allows you to retrieve the name of the Fetching Strategy you want, by overriding toString method 
     * public class AbstractFetchingStrategy implements FetchingStrategy { 
     * 
     *  @Override 
     *  public String toString() { 
     *   return getClass().getSimpleName(); 
     *  } 
     * 
     * } 
     * 
     * Because there is no need to create an instance outside our repository, we mark it as private 
     * Notive each FetchingStrategy must match a named query 
     */ 
    private static class GIFT_CARDS_WITH_BUYER extends AbstractFetchingStrategy {}  
    private static class GIFT_CARDS_WITHOUT_NO_RELATIONSHIP extends AbstractFetchingStrategy {} 
} 

现在我们外部化的多我们的命名查询 - 和可读性和可维护性 - xml文件

// app.hbl.xml 
<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 
<hibernate-mapping> 
    <query name="GIFT_CARDS_WITH_BUYER"> 
     <![CDATA[ 
      from 
       GiftCard c 
      left join fetch 
       c.buyer 
      where 
       c.recipientNotificationRequested = 1 
     ]]> 
    </query> 
    <query name="GIFT_CARDS_WITHOUT_NO_RELATIONSHIP"> 
     <![CDATA[ 
      from 
       GiftCard 
     ]]> 
    </query> 
</hibernate-mapping> 

所以,如果你想找回你礼金券与买家,只需拨打

Repository<GiftCard, GiftCard, String> giftCardRepository; 

List<GiftCard> giftCardList = giftCardRepository.findAll(GiftCardRepository.GIFT_CARDS_WITH_WITH_BUYER); 

而且没有任何关系,获取我们的礼金券,只需拨打

List<GiftCard> giftCardList = giftCardRepository.findAll(GiftCardRepository.GIFT_CARDS_WITHOUT_NO_RELATIONSHIP); 

或使用进口静态

import static packageTo.GiftCardRepository.*; 

And

List<GiftCard> giftCardList = giftCardRepository.findAll(GIFT_CARDS_WITHOUT_NO_RELATIONSHIP); 

我希望它对你有用!

+0

非常有趣...这是伟大的思想食物。它提出了一个侧面的问题。我如何执行一个查询,不会获取目标GiftCard以外的任何关联对象? – 2010-05-30 06:36:41

+0

@Ben Benson请参阅GiftCardRepository(最后一行),在底部指定查询文件和附加代码。如果我的回答满足您的需求,请将其标记为已接受。谢谢 – 2010-05-31 12:45:53

2

在JPA默认为ManyToOne协会提取类型是渴望(即非懒惰),所以你可以尝试用:

@ManyToOne(fetch=FetchType.LAZY) 

然后在任何JPA查询中,可以使用left join fetch热切地获取关联。