Spring Jpa 规范和渴望加载
Posted
技术标签:
【中文标题】Spring Jpa 规范和渴望加载【英文标题】:Spring Jpa Specification and Eager loading 【发布时间】: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);
【问题讨论】:
如果你想通过加载门票类别看到这个答案:***.com/questions/15359306/… @Si mo,我找不到分类! @SkorpEN 与 JPA 规范无关。 @AndréOnuki Spring Jpa 规范更多关于 JpaRepository 从链接“Jpa Specification”到 SpringData-jpa。如果您认为应该更改链接,请更改它。无论如何,这个问题是在标签和链接中看到的 spring-data-jpa。 @SkorpEN 我理解这种困惑。问题是关于 JPA 的规范类,而不是 JPA 的规范。这个问题确实是关于 JPA 的,但是您发布的链接与 Specification 类无关。 【参考方案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】:正如他们所说,*** 给予,*** 接受...... 我很久以前就把这门课关掉了,请随意回收它..
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
/**
* *** 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>());
/**
* ***s 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 的所有集合的技巧。
【讨论】:
以上是关于Spring Jpa 规范和渴望加载的主要内容,如果未能解决你的问题,请参考以下文章