JPA:我如何将 属性 映射到基于其他表中的 COUNT 的派生列(不会产生 n+1 select 问题?)

JPA: how can i map a property to a derived column that is based on a COUNT from other tables (Without incurring in n+1 select problems?)

这些是我的项目中定义的实体:

Post

@Entity
public class Post implements Serializable {
    public enum Type {TEXT, IMG}

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Integer id;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "section_id")
    protected Section section;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "author_id")
    protected User author;

    @Column(length = 255, nullable = false)
    protected String title;

    @Column(columnDefinition = "TEXT", nullable = false)
    protected String content;

    @Enumerated(EnumType.STRING)
    @Column(nullable = false)
    protected Type type;

    @CreationTimestamp
    @Column(nullable = false, updatable = false, insertable = false)
    protected Instant creationDate;

    @Column(insertable = false, updatable = false)
    protected Integer votes;  
    
    /*accessor methods*/
}

评论

@Entity
public class Comment implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Integer id;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "post_id")
    protected Post post;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "author_id")
    protected User author;

    @ManyToOne(fetch = FetchType.LAZY, optional = true)
    @JoinColumn(name = "parent_comment_id")
    protected Comment parentComment;

    @Column(columnDefinition = "TEXT", nullable = false)
    protected String content;

    @CreationTimestamp
    @Column(nullable = false, updatable = false, insertable = false)
    protected Instant creationDate;

    @Column(insertable = false, updatable = false)
    protected Integer votes;

    @Column(insertable = false, updatable = false)
    protected String path;
    
    /*accessor methods*/
}  

如您所见,仅从 child 的角度跟踪聚合:由于设计选择,没有 @ManyToOne 关系。

但是,我想向 Post 实体添加一个 commentCount 字段。这个字段应该被急切地加载(因为它总是在我的用例中被读取并且 COUNT 语句不是 that 昂贵......我猜)

这些是我目前知道的选项:

什么是有效的解决方案?我正在使用 Hibernate,但我更喜欢 implementation-agnostic 解决方案(不过 Implementation-specific 选项不会被忽略)

使用 @Formula 不会导致任何 N+1 select 问题(不同于 @PostLoad),因为指定的表达式是作为初始 [=25] 的一部分计算的=] 查询.

(事实上,您需要启用 Hibernates 字节码增强才能 lazy-load 计算的 @Formula 属性: Controlling lazy/eager loading of @Formula columns dynamically

因此,即使它是一个需要原生 SQL 的 Hibernate-specific 功能,@Formula 可能是实现这一点的好而简单的方法。

如果相关子查询的性能缺陷变得很明显,并且在某些情况下不需要计算 属性,您可以另外创建一个仅包含所需属性的 DTO 投影。