如何在DB会话外序列化延迟加载的Hibernate集合(如PersistentSet)



我正在开发一个Spring MVC facade来访问许多服务。目前还没有实施DTO,由于规模巨大,目前还没有这样做的选择

Jackson直接对返回到控制器的实体进行序列化,这些实体是对服务中的方法进行事务调用的结果,这些方法通过ORM(Hibernate(从DB中获取实体。

问题来自于具有从一对多或多对多关系的集合属性(如Sets(的实体,Hibernate返回为PersistentCollections(如PersistentSet(,并且延迟加载,因此,不能在DB会话的范围之外读取(当Jackson试图序列化来自Controller的响应时(。

理想情况下,我希望Hibernate返回Java代理集合(HibernateProxy(,维护对它们包装的实体的引用(标识符(。还可以继续使用专门的数据结构(如PersistentCollection(,但保持对项目的引用被包装,因为一旦包装,它们只能从BD会话中的映射中检索,如果没有它,集合的密钥是完全无用的(为什么它喜欢这样?如果我们不希望整个项目,只是它的标识符被序列化为引用呢?叹气(。

我想知道。。。

是否可以强制Hibernate返回封装实体的代理的Java集合?

如果没有,是否可以扩展Hibernate集合(如PersistentCollection(来维护对封装实体的引用,以便在专门的Jackson Hibernate序列化程序中读取它们?

如果没有,除了实体本身之外,是否可以在关闭BD会话之前将Hibernate集合转换为Java集合,而不使用其他数据结构(即将集合转换回Java类型(?

好吧,您可以使用例如HQLselect u from User u join fetch u.groups来连接获取集合,并使用@JsonView(ReferenceJsonView.class)interface ReferenceJsonView { Integer getId(); }来注释User实体中的groups属性,但这将获取超出需要的状态。我建议您考虑实现适当的DTO,这可以用Blaze Persistence实体视图很容易地完成。

Blaze Persistence是JPA之上的查询生成器,它支持JPA模型之上的许多高级DBMS功能。我在上面创建了实体视图,以便在JPA模型和自定义接口定义的模型之间进行简单的映射,比如类固醇上的Spring数据投影。其思想是,您可以按照自己喜欢的方式定义目标结构,并通过JPQL表达式将属性(getter(映射到实体模型。由于属性名称被用作默认映射,所以您基本上不需要显式映射,因为80%的用例都有作为实体模型子集的DTO。

假设你有一个像这样的实体模型

@Entity
public class User {
@Id
Integer id;
String username;
@ONeToMany
Set<Group> groups;
}
@Entity
public class Group {
@Id
Integer id;
String name;
}

您的模型的DTO映射可能看起来像下面的一样简单

@EntityView(User.class)
interface UserDto {
Integer getId();
String getUsername();
Set<GroupDto> getGroups();
}
@EntityView(Group.class)
interface GroupDto {
Integer getId();
}

查询是将实体视图应用于查询的问题,最简单的是按id进行查询。

UserDto dto = entityViewManager.find(entityManager, UserDto.class, id);

但是Spring Data集成允许您像使用Spring Data Projections一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-数据特征

它只会获取您告诉它要获取的映射,并且所有映射都会在启动时进行验证,因此在运行时不会出错。

最新更新