避免使用Hibernate Criteria或HQL查询进行二级选择或连接 [英] Avoiding secondary selects or joins with Hibernate Criteria or HQL query

查看:131
本文介绍了避免使用Hibernate Criteria或HQL查询进行二级选择或连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法优化Hibernate查询以避免执行连接或次级选择。



执行Hibernate查询(criteria或hql)时,如下所示:

  return getSession()。createQuery((from GiftCard as card where card.recipientNotificationRequested = 1)。 

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

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



  @Entity 
@Table(name =giftCards)
公共类GiftCa rd实现Serializable
{
private static final long serialVersionUID = 1L;

私人字符串id_;
私人用户buyer_;
private boolean isRecipientNotificationRequested_;


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

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

@ManyToOne
@JoinColumn(name = buyerUserId)
@NotFound(动作= NotFoundAction.IGNORE)
公共用户getBuyer()
{
return this.buyer_;
}
public void setBuyer(用户买家)
{
this.buyer_ =买家;
}

@Column(name = isRecipientNotificationRequested,可为空=假,columnDefinition = TINYINT)
公共布尔isRecipientNotificationRequested()
{
返回this.isRecipientNotificationRequested_;
}

公共无效setRecipientNotificationRequested(布尔isRecipientNotificationRequested)
{
this.isRecipientNotificationRequested_ = isRecipientNotificationRequested;



解决方案


我想要一个解决方案,当我执行查询时,我可以控制延迟加载的内容

>

如果您有这样的映射

  @Entity 
public class GiftCard实现Serializable {

私有用户买方;

@ManyToOne
@JoinColumn(name =buyerUserId)
public User getBuyer(){
return this.buyer;
}
}

任何* ToOne关系,例如@OneToOne和@ ManyToOne,默认情况下是FetchType.EAGER,这意味着它总是被抓取。但是,这不可能是你想要的。你所说的我可以控制什么是懒惰加载可以翻译为获取策略 POJO in Action 书籍支持像这样的模式(通知方法签名)

  public class GiftCardRepositoryImpl实现GiftCardRepository {

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





因此根据你的用例,你可以创建自己的 find ... With ... And ... 方法。它会照顾到正是你想要的

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



 公共接口库< 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);
清单< INSTANCE_CLASS>找到所有();
清单< INSTANCE_CLASS> findAll(FetchingStrategy fetchingStrategy);
清单< INSTANCE_CLASS> findAll(int pageNumber,int pageSize);
清单< INSTANCE_CLASS> findAll(int pageNumber,int pageSize,FetchingStrategy fetchingStrategy);
清单< INSTANCE_CLASS> findAllByCriteria(Criteria criteria);
清单< INSTANCE_CLASS> findAllByCriteria(条件标准,FetchingStrategy fetchingStrategy);
清单< INSTANCE_CLASS> findAllByCriteria(int pageNumber,int pageSize,Criteria条件);
清单< INSTANCE_CLASS> findAllByCriteria(int pageNumber,int pageSize,Criteria criteria,FetchingStrategy fetchingStrategy);




$ b

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

  public abstract class AbstractRepository< INSTANCE_CLASS,UPDATABLE_INSTANCE_CLASS,PRIMARY_KEY_CLASS>实现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(){
抛出新的UnsupportedOperationException(还不支持。);
}

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(暂不支持。);
}

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

public List< INSTANCE_CLASS> findAllByCriteria(条件标准){
抛出新的UnsupportedOperationException(还不支持。);
}

public List< INSTANCE_CLASS> findAllByCriteria(条件标准,FetchingStrategy fetchingStrategy){
抛出新的UnsupportedOperationException(尚未支持。);
}

public List< INSTANCE_CLASS> findAllByCriteria(int pageNumber,int pageSize,Criteria criteria){
抛出新的UnsupportedOperationException(还不支持。);
}

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


$ b $ / code $ / pre

因此你的GiftCardRepository可以被重新设计,书写为(请参阅扩展而不是实现),仅覆盖您真正想要的内容

  public class GiftCardRepository扩展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();

公共列表< GiftCard> findAll(FetchingStrategy fetchingStrategy){
sessionFactory.getCurrentSession()。getNamedQuery(fetchingStrategy.toString())。list();


$ b / **
* FetchingStrategy只是一个标记界面
* public interface FetchingStrategy {}
*
*与AbstractFetchingStrategy允许您通过覆盖toString方法
以获取你想要的数据抓取策略的名称,*公共类AbstractFetchingStrategy实现FetchingStrategy {
*
* @覆盖
*公共字符串toString(){
* return getClass()。getSimpleName();
*}
*
*}
*
*因为不需要在我们的仓库之外创建一个实例,所以我们将它标记为private
* Notive每个FetchingStrategy必须匹配命名查询
* /
私有静态类GIFT_CARDS_WITH_BUYER扩展AbstractFetchingStrategy {}
私有静态类GIFT_CARDS_WITHOUT_NO_RELATIONSHIP扩展AbstractFetchingStrategy {}
}

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

  // app.hbl.xml 
<?xml version =1.0encoding =UTF-8?>
<!DOCTYPE hibernate-mapping PUBLIC - // Hibernate / Hibernate Mapping DTD 3.0 // ENhttp://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd\">
< hibernate-mapping>
< query name =GIFT_CARDS_WITH_BUYER>
<![CDATA [
from
GiftCard c
左连接读取
c.buyer
其中
c.recipientNotificationRequested = 1
]]>
< / query>
< query name =GIFT_CARDS_WITHOUT_NO_RELATIONSHIP>
<![CDATA [
from
GiftCard
]]>
< / query>
< / hibernate-mapping>

因此,如果您想要将GiftCard与买方取回,请致电

 存储库<礼品卡,礼品卡,字符串> giftCardRepository; 

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

为了检索我们的礼品卡而没有任何关系,只需拨打

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

或者使用import static

  import static packageTo.GiftCardRepository。*; 



 列表与LT;礼金券> giftCardList = giftCardRepository.findAll(GIFT_CARDS_WITHOUT_NO_RELATIONSHIP); 

我希望它对您有用!


I am having trouble optimizing Hibernate queries to avoid performing joins or secondary selects.

When a Hibernate query is performed (criteria or hql), such as the following:

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

... and the where clause examines properties that do not require any joins with other tables... but Hibernate still performs a full join with other tables (or secondary selects depending on how I set the fetchMode).

The object in question (GiftCard) has a couple ManyToOne associations that I would prefer to be lazily loaded in this case (but not necessarily all cases). I want a solution that I can control what is lazily loaded when I perform the query.

Here's what the GiftCard Entity looks like:

@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;
 }
}

解决方案

As said

I want a solution that I can control what is lazily loaded when I perform the query

If you have a mapping like this one

@Entity
public class GiftCard implements Serializable {

    private User buyer;

    @ManyToOne
    @JoinColumn(name="buyerUserId")
    public User getBuyer() {
        return this.buyer;
    }
}

Any *ToOne relationship, such as @OneToOne and @ManyToOne, is, by default, FetchType.EAGER which means it will be always fetched. But, it could not be what you want. What you say as I can control what is lazily loaded can be translated as Fetching Strategy. POJO in Action book supports a pattern like this one (Notice method signature)

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();
     }

}

So based on your use case, you can create your own find...With...And... method. It will take care of fetching just what you want

But it has a problem: It does not support a generic method signature. For each @Entity repository, you have to define your custom find...With...And method. Because of that, i show you how i define a generic repository

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);

}

But, sometimes, you do not want all of methods defined by generic Repository interface. Solution: create an AbstractRepository class which will implement a dummy repository. Spring Framework, for instance, heavily use this kind of pattern Interface >> 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.");
    }

}

So your GiftCardRepository can be re-written as (See extends instead of implements) and just overrides what you really want

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 {}
}

Now we externalize our named query in a multiline - and readable and maintainable - xml file

// 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>

So if you want to retrieve you GiftCard with Buyer, just call

Repository<GiftCard, GiftCard, String> giftCardRepository;

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

And to retrieve our GiftCard without no relationship, just call

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

or use import static

import static packageTo.GiftCardRepository.*;

And

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

I hope it can be useful to you!

这篇关于避免使用Hibernate Criteria或HQL查询进行二级选择或连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆