Mat*_*ann 132 java spring hibernate jpa spring-data
我有一个Person类:
@Entity
public class Person {
@Id
@GeneratedValue
private Long id;
@ManyToMany(fetch = FetchType.LAZY)
private List<Role> roles;
// etc
}
Run Code Online (Sandbox Code Playgroud)
与多对多的关系是懒惰的.
在我的控制器中我有
@Controller
@RequestMapping("/person")
public class PersonController {
@Autowired
PersonRepository personRepository;
@RequestMapping("/get")
public @ResponseBody Person getPerson() {
Person person = personRepository.findOne(1L);
return person;
}
}
Run Code Online (Sandbox Code Playgroud)
PersonRepository就是这个代码,根据本指南编写
public interface PersonRepository extends JpaRepository<Person, Long> {
}
Run Code Online (Sandbox Code Playgroud)
但是,在这个控制器中,我实际上需要惰性数据.如何触发加载?
试图访问它将失败
未能懒惰地初始化角色集合:no.dusken.momus.model.Person.roles,无法初始化代理 - 没有会话
或其他例外取决于我尝试的内容.
我的xml描述,如果需要的话.
谢谢.
zag*_*gyi 191
你将不得不作出对延迟集合的显式调用,以初始化(通常的做法是调用.size()用于此目的).在Hibernate中有一个专门的this(Hibernate.initialize())方法,但JPA没有相应的方法.当然,当会话仍然可用时,您必须确保调用已完成,因此请使用注释控制器方法@Transactional.另一种方法是在Controller和Repository之间创建一个中间服务层,它可以公开初始化延迟集合的方法.
请注意,上述方案很容易,但会导致两种不同的查询数据库(一个用于用户,另一个用于它的角色).如果要实现更好的性能,请将以下方法添加到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);
}
Run Code Online (Sandbox Code Playgroud)
此方法将使用JPQL的fetch join子句在单个往返数据库中急切加载角色关联,从而减轻上述解决方案中两个不同查询所带来的性能损失.
rak*_*pan 33
虽然这是一篇旧帖子,但请考虑使用@NamedEntityGraph(Javax Persistence)和@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
}
Run Code Online (Sandbox Code Playgroud)
然后是如下的弹簧回购
@RepositoryRestResource(collectionResourceRel = "Employee", path = "Employee")
public interface IEmployeeRepository extends PagingAndSortingRepository<EmployeeEntity, String> {
@EntityGraph(value = "employeeAuthorities", type = EntityGraphType.LOAD)
EmployeeEntity getByUsername(String userName);
}
Run Code Online (Sandbox Code Playgroud)
Jos*_*tin 13
你有一些选择
更多的工作,最好的表现.
减少工作量,通常在网络环境中可以接受.
减少工作量,当OEMIV不可用时很有用,例如在Swing应用程序中,但在存储库实现上也可能有用,可以一次性初始化任何实体.
对于最后一个选项,我编写了一个实用程序类JpaUtils来在某些deph中初始化实体.
例如:
@Transactional
public class RepositoryHelper {
@PersistenceContext
private EntityManager em;
public void intialize(Object entity, int depth) {
JpaUtils.initialize(em, entity, depth);
}
}
Run Code Online (Sandbox Code Playgroud)
JpaRepositorySpring DataJpaRepository定义了以下两种方法:
但是,就您而言,您没有致电getOne或findById:
Person person = personRepository.findOne(1L);
Run Code Online (Sandbox Code Playgroud)
因此,我假设该findOne方法是您在PersonRepository. 但是,该findOne方法在您的情况下不是很有用。由于您需要Person随同一起获取roles集合,因此最好使用findOneWithRoles方法来代替。
您可以定义一个PersonRepositoryCustom接口,如下所示:
public interface PersonRepository
extends JpaRepository<Person, Long>, PersonRepositoryCustom {
}
public interface PersonRepositoryCustom {
Person findOneWithRoles(Long id);
}
Run Code Online (Sandbox Code Playgroud)
并像这样定义它的实现:
public class PersonRepositoryImpl implements PersonRepositoryCustom {
@PersistenceContext
private EntityManager entityManager;
@Override
public Person findOneWithRoles(Long id)() {
return entityManager.createQuery("""
select p
from Person p
left join fetch p.roles
where p.id = :id
""", Person.class)
.setParameter("id", id)
.getSingleResult();
}
}
Run Code Online (Sandbox Code Playgroud)
就是这样!
| 归档时间: |
|
| 查看次数: |
175284 次 |
| 最近记录: |