【问题标题】:Spring Jpa Specification and Eager loadingSpring Jpa 规范和渴望加载
【发布时间】:2016-03-14 16:06:46
【问题描述】:

我如何通过Jpa Specification获得票务列表及其类别

示例模型:

@Entity
@Table(name = "tickets")
public class Ticket {

@Id
private Integer id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "category_id")
private Category 
}

服务方式:

public Page<Ticket> findAll(Pageable pageable) {
        return ticketRepository.findAll((root, query, cb) -> {
            root.join("category");
            return query.getRestriction();
        }, pageable);
}

【问题讨论】:

  • 如果你想通过加载门票类别看到这个答案:stackoverflow.com/questions/15359306/…
  • @Si mo,我找不到分类!
  • @SkorpEN 与 JPA 规范无关。
  • @AndréOnuki Spring Jpa 规范更多关于 JpaRepository 从链接“Jpa Specification”到 SpringData-jpa。如果您认为应该更改链接,请更改它。无论如何,这个问题是在标签和链接中看到的 spring-data-jpa。
  • @SkorpEN 我理解这种困惑。问题是关于 JPA 的规范类,而不是 JPA 的规范。这个问题确实是关于 JPA 的,但是您发布的链接与 Specification 类无关。

标签: spring jpa spring-boot spring-data-jpa


【解决方案1】:

我能够通过使用 fetch 而不是 join 来预先加载集合。

public Page<Ticket> findAll(Pageable pageable) {
    return ticketRepository.findAll((root, query, cb) -> {
        root.fetch("category");
        return query.getRestriction();
    }, pageable);
}

fetch 方法将使用默认的连接类型(内部)。如果要加载没有类别的票证,则必须将JoinType.LEFT 作为第二个参数传递。

【讨论】:

    【解决方案2】:

    要加载Lazy 关系,您有一些方法。最常用的一些是:

    计算要加载的列表

    那是什么?所以,你需要用关系“做点什么”,这样它才能被加载。所以你可以打电话

    List<Tiket> tickets = ticketRepository.findAll();
    for(Ticket t : tickets){
       t.category.name;
    }
    

    这样,您可以强制 JPA 查询类别。可是等等!这样做的问题是你会有很多额外的查询(在一个大场景中,这可能是一个性能问题)。因此,大多数情况下,最好的解决方案是另一种解决方案。

    自定义 JPA 查询

    您应该进入存储库接口并创建一个带有@Query 注释的新方法来获取关系。比如:

    SELECT t FROM Ticket t JOIN FETCH t.category
    

    【讨论】:

    • 这个答案与JPA规范无关。
    【解决方案3】:

    正如他们所说,stackoverflow 给予,stackoverflow 接受...... 我很久以前就把这门课关掉了,请随意回收它..

    import java.beans.PropertyDescriptor;
    import java.lang.reflect.InvocationTargetException;
    import java.util.ArrayList;
    import java.util.Collection;
    
    import org.apache.commons.beanutils.PropertyUtils;
    import org.hibernate.Hibernate;
    
    public class BeanLoader {
        /**
         * StackOverflow safe, if called before json creation, cyclic object must be avoided
         */
        public static void eagerize(Object obj)  {
            if(!Hibernate.isInitialized(obj))
                Hibernate.initialize(obj);
            PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj);
            for (PropertyDescriptor propertyDescriptor : properties) {
                Object origProp = null;
                try {
                    origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName());
                } catch (IllegalAccessException e) {
                    // Handled, but hopefully dead code  
                    origProp=null;
                } catch (InvocationTargetException e) {
                    // Single catch for obsolete java developers!
                    origProp=null;
                } catch (NoSuchMethodException e) {
                    // Single catch for obsolete java developers!
                    origProp=null;
                }
                if (origProp != null 
                        && origProp.getClass().getPackage().toString().contains("domain")) {
                    eagerize(origProp, new ArrayList<String>());
                }
                if (origProp instanceof Collection) {               
                    for (Object item : (Collection) origProp) {
                        if (item.getClass().getPackage().toString().contains("domain")){
                            eagerize(item, new ArrayList<String>());
                        }
                    }
                }
            }
        }
    
        /**
         * StackOverflows if passed a bean containing cyclic fields. Call only if sure that this won't happen!
         */
        public static void eagerizeUnsafe(Object obj)  {
            if(!Hibernate.isInitialized(obj))
                Hibernate.initialize(obj);
            PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj);
            for (PropertyDescriptor propertyDescriptor : properties) {
                Object origProp = null;
                try {
                    origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName());
                } catch (IllegalAccessException e) {
                    // Handled, but hopefully dead code  
                    origProp=null;
                } catch (InvocationTargetException e) {
                    // Single catch for obsolete java developers!
                    origProp=null;
                } catch (NoSuchMethodException e) {
                    // Single catch for obsolete java developers!
                    origProp=null;
                }
                if (origProp != null 
                        && origProp.getClass().getPackage().toString().contains("domain")) {
                    eagerize(origProp);
                }
                if (origProp instanceof Collection) {               
                    for (Object item : (Collection) origProp) {
                        if (item.getClass().getPackage().toString().contains("domain")){
                            eagerize(item);
                        }
                    }
                }
            }
        }
    
        private static void eagerize(Object obj, ArrayList<String> visitedBeans)  {
            if (!visitedBeans.contains(obj.getClass().getName())){
                visitedBeans.add(obj.getClass().getName());
            } else {
                return;
            }
            if(!Hibernate.isInitialized(obj))
                Hibernate.initialize(obj);
            PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj);
            for (PropertyDescriptor propertyDescriptor : properties) {
                Object origProp = null;
                try {
                    origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName());
                } catch (IllegalAccessException e) {
                    // Handled, but hopefully dead code  
                    origProp=null;
                } catch (InvocationTargetException e) {
                    // Single catch for obsolete java developers!
                    origProp=null;
                } catch (NoSuchMethodException e) {
                    // Single catch for obsolete java developers!
                    origProp=null;
                }
                if (origProp != null 
                        && origProp.getClass().getPackage().toString().contains("domain")) {
                    eagerize(origProp, visitedBeans);
                }
                if (origProp instanceof User){
                    ((User) origProp).setRelatedNra(null);
                    User u=(User) origProp;
                    if (u.getRelatedMps()!=null)
                        u.getRelatedMps().clear();
                    if (u.getRelatedDps()!=null)
                        u.getRelatedDps().clear();
                }
                if (origProp instanceof Collection) {               
                    for (Object item : (Collection) origProp) {
                        if (item.getClass().getPackage().toString().contains("domain")){
                            eagerize(item, (ArrayList<String>) visitedBeans.clone());
                        }
                    }
                }
            }
        }
    }
    

    根据需要对其进行修改。您将调用的方法是“eagerizeUnsafe”。 YMMV,但这应该是让延迟初始化 bean 的所有集合的技巧。

    【讨论】:

      猜你喜欢
      • 2015-03-10
      • 1970-01-01
      • 2013-05-06
      • 1970-01-01
      • 2013-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-29
      相关资源
      最近更新 更多