使用代理与Hibernate运行时字节码增强。

3

我正在使用Spring Boot 2.7.5和Hibernate 5.6.12.Final,并通过hibernate-enhance-maven-plugin在构建时应用字节码增强。它非常好用,可以防止急切地获取@OneToOne关系,如此处所述https://vladmihalcea.com/hibernate-lazytoone-annotation/

然而,我发现所有的懒惰关系都不再使用代理,而是在我使用getter(已经在构建时由maven插件进行了仪器化)时从数据库中获取。基本上,我想做的是仍然使用带有字节码增强的代理。类似的东西在运行时是可用的https://in.relation.to/2019/07/30/bytecode-proxy/,但我找不到一种在构建时实现它的方法。

简单介绍一下,我需要惰性加载属性的代理,因为这样可以让我根据代理是否被初始化,在实体-> dto映射器(使用Mapstruct)中应用自定义逻辑。有些情况下,如果Hibernate会话可用(并防止LazyInitializationException),必须手动触发初始化。

非常感谢您的任何建议!


你可以使用属性 lazy="proxy|no-proxy|false" - muhammed ozbilici
请问您能指示我在哪里设置这个属性吗?我已经尝试在application.yml中设置spring.jpa.hibernate.bytecode.allow_enhancement_as_proxy: true,但它没有生效。 - Blockost
1
@Blockost 你有检查过 org.hibernate.Hibernate#isPropertyInitialized 方法吗? - Andrey B. Panfilov
我之前不知道这个方法,感谢你指出来。这对我以后肯定会有所帮助!然而,我的问题是属性getter在映射器中被调用,并且并不能保证始终有Hibernate会话可用。因此,我在那里遇到了LazyInitializationException。映射器是由Mapstruct在构建时生成的,因此我无法完全控制它们(而且我也不想在Mapstruct方面添加太多逻辑)。 - Blockost
只是为了扩展@muhammedozbilici的建议,文档实际上向您展示了您可以选择退出每个特定增强的方式。并且,由于您正在使用Maven插件的编译时增强,因此Spring属性显然不起作用。 - crizzis
或者,点击此处查看如何让MapStruct与Hibernate的延迟关联一起工作 - 简而言之,您确实可以对映射器进行一些控制,足以使其正常工作。 - crizzis
1个回答

0

如果您想避免DTO映射中的LazyInitializationException,您应该尝试避免在Java代码中进行映射,而是使用可以将映射降至HQL/SQL级别的解决方案。

我认为这是Blaze-Persistence Entity Views的完美用例。

我创建了这个库,以便轻松地在JPA模型和自定义接口或抽象类定义的模型之间进行映射,类似于强化版的Spring Data Projections。其思想是您可以根据自己的喜好定义目标结构(领域模型),并通过JPQL表达式将属性(getter)映射到实体模型。

使用Blaze-Persistence Entity-Views的可能用例的DTO模型如下:

@EntityView(User.class)
public interface UserDto {
    @IdMapping
    Long getId();
    String getName();
    Set<RoleDto> getRoles();

    @EntityView(Role.class)
    interface RoleDto {
        @IdMapping
        Long getId();
        String getName();
    }
}

查询是将实体视图应用于查询的问题,最简单的查询仅通过ID进行查询。

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

Spring Data集成使您几乎可以像使用Spring Data投影一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

Page<UserDto> findAll(Pageable pageable);

最好的部分是,它只会获取实际上必要的状态!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接