在弹簧投影中获取惰性属性

2022-09-03 03:03:16

我目前正在尝试评估使用Spring Data JPA的可能性。

尝试使用投影,我目前陷入了尝试获取特定属性 Eager 的困境。

我有一个简单的实体,它懒惰地引用另一个具有外键的实体。我现在想为前一个实体定义不同的预测。“基元”属性很好地投影到投影界面中,但尝试投影另一个实体/投影会导致它仍然被延迟加载。

我现在想告诉Spring/JPA,要热切地在投影中加载实体/投影。一种可能的方法是使用EntityGraphs(它们运行良好),但是我必须使用不同的图形为每个方法创建存储库。问题是还有哪些其他方法?

例:

实体买家:

@Entity
public class Buyer {
    private Integer id;
    private String someProperty;
    private User user;

    ...

    @OneToOne(
        fetch = FetchType.LAZY)
    @JoinColumn(
        name = "CAB_USR_ID",
        referencedColumnName = "ID",
        updatable = false,
        nullable = true,
        foreignKey = @ForeignKey(name = "FK_CAB_USR"))
    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

实体用户:

@Entity
public class User {

    private Integer id;
    private String name;

    ...

}

投影买家

public interface BuyerCProjection {
    Integer getId();
    UserProjection getUser();
}

投影用户

public interface UserProjection {

    Integer getId();
    String getName();
}

我想使用的存储库

public interface BuyerRepository extends Repository<Buyer, Integer> {

    <T> List<T> findBy(Class<T> t);
}

答案 1

我不认为有办法指示JPA/Hibernate使用投影急切地获取。投影在执行读取查询后应用,因此修改查询为时已晚。

有一个折衷的解决方案,使用启用了该功能的 jackson-datatype-hibernate 模块。这将强制初始化并返回投影中的所有延迟加载对象。FORCE_LAZY_LOADING

请注意,这不如使用实体图或 编写自定义查询有效。它的行为与调用每个延迟加载的对象相同,执行另一个选择查询。因此,它会导致 N+1 次选择。但这可能是一个很好的入门方法。当某些内容开始变慢时,您仍可以通过编写连接-提取或实体图查询进行优化。JOIN FETCHHibernate.initialize


答案 2

这是一个迟到的答案,但是,我希望它可以帮助其他人。

“@EntityGraph”注释可以提供用户信息,以便在您的案例中紧急加载。

没有经过测试,但我想下面的存储库方法可以适用于您的情况。我不确定您预期的泛型方法实现的实现。

public interface BuyerRepository extends Repository<Buyer, Integer> {

    @EntityGraph(attributePaths = {"user"})
    List<BuyerCProjection> findProjectedById(Integer id);
}

您可以在此处找到有关如何使用实体图的更详细说明


推荐