如何从我的控制器中加载Hibernate / JPA中的延迟获取项目

我有一个Person类:

@Entity public class Person { @Id @GeneratedValue private Long id; @ManyToMany(fetch = FetchType.LAZY) private List<Role> roles; // etc } 

有一个懒惰的多对多的关系。

在我的控制器中,我有

 @Controller @RequestMapping("/person") public class PersonController { @Autowired PersonRepository personRepository; @RequestMapping("/get") public @ResponseBody Person getPerson() { Person person = personRepository.findOne(1L); return person; } } 

而PersonRepository就是这个代码,按照这个指南写的

 public interface PersonRepository extends JpaRepository<Person, Long> { } 

但是,在这个控制器中我实际上需要懒惰数据。 我怎样才能触发它的加载?

试图访问它将失败

未能懒惰地初始化一个angular色集合:no.dusken.momus.model.Person.roles,无法初始化代理 – 没有会话

或其他例外取决于我的尝试。

我的xml描述 ,在需要的情况下。

谢谢。

你将不得不对lazy集合进行明确的调用来初始化它(通常的做法是为此调用.size() )。 在Hibernate中有一个专用的方法( Hibernate.initialize() ),但是JPA没有这个方法。 当然,你必须确保调用完成,当会话仍然可用时,用@Transactional注释你的控制器方法。 另一种方法是在Controller和Repository之间创build一个中间服务层,以便公开初始化懒惰集合的方法。

更新:

请注意,上面的解决scheme很简单,但会导致对数据库的两个不同的查询(一个用于用户,另一个用于angular色)。 如果您想要获得更好的性能,请将以下方法添加到您的Spring Data JPA存储库接口中:

 public interface PersonRepository extends JpaRepository<Person, Long> { @Query("SELECT p FROM Person p JOIN FETCH p.roles WHERE p.id = (:id)") public Person findByIdAndFetchRolesEagerly(@Param("id") Long id); } 

这个方法将使用JPQL的fetch连接子句来在数据库中一次往返加载angular色关联,从而减轻上述解决scheme中两个不同查询产生的性能损失。

虽然这是一个旧的post,请考虑使用@NamedEntityGraph(Javax持久性)和@EntityGraph(Spring Data JPA)。 组合起作用。

 @Entity @Table(name = "Employee", schema = "dbo", catalog = "ARCHO") @NamedEntityGraph(name = "employeeAuthorities", attributeNodes = @NamedAttributeNode("employeeGroups")) public class EmployeeEntity implements Serializable, UserDetails { // your props } 

然后如下所示的春季回购

 @RepositoryRestResource(collectionResourceRel = "Employee", path = "Employee") public interface IEmployeeRepository extends PagingAndSortingRepository<EmployeeEntity, String> { @EntityGraph(value = "employeeAuthorities", type = EntityGraphType.LOAD) EmployeeEntity getByUsername(String userName); } 

你有一些select

  • 在存储库中写一个方法,按照RJ的build议返回一个初始化的实体。

更多的工作,最好的performance。

  • 使用OpenEntityManagerInViewFilter保持会话打开整个请求。

较less的工作,通常可以在networking环境中使用。

  • 需要时使用助手类来初始化实体。

当OEMIV没有select时,例如在Swing应用程序中,工作量较less,有用,但是在存储库实现中也可以用于一次初始化任何实体。

对于最后一个选项,我写了一个实用程序类JpaUtils来初始化某些实体的实体。

例如:

 @Transactional public class RepositoryHelper { @PersistenceContext private EntityManager em; public void intialize(Object entity, int depth) { JpaUtils.initialize(em, entity, depth); } } 

它只能在交易过程中被延迟加载。 所以你可以访问你的仓库中的集合,这个集合有一个事务 – 或者我通常做的是一个get with association ,或者设置fetchmode为渴望。

我认为你需要OpenSessionInViewFilter来保持你的会话在视图渲染过程中打开(但这不是太好的做法)。

你可以这样做:

 @Override public FaqQuestions getFaqQuestionById(Long questionId) { session = sessionFactory.openSession(); tx = session.beginTransaction(); FaqQuestions faqQuestions = null; try { faqQuestions = (FaqQuestions) session.get(FaqQuestions.class, questionId); Hibernate.initialize(faqQuestions.getFaqAnswers()); tx.commit(); faqQuestions.getFaqAnswers().size(); } finally { session.close(); } return faqQuestions; } 

只要在你的控制器中使用faqQuestions.getFaqAnswers()。size(),你将得到大小,如果懒惰的初始化列表,而没有获取列表本身。