当前位置: 首页 > 知识库问答 >
问题:

JPA:如何将属性映射到基于其他表的计数的派生列(而不产生n 1选择问题?)

胡星汉
2023-03-14

以下是我的项目中定义的实体:

@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*/
}  

如您所见,聚合只从孩子的角度进行跟踪:由于设计选择,没有@manytone关系。

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

以下是我目前知道的选项:

>

  • 使用@公式@PostLoad注释:将有N 1选择语句

    检索帖子,然后调用另一个存储库方法,该方法使用中的操作符,将所有检索到的帖子作为参数:

      select post, count(comment) from Post post, Comment comment where comment.post in (:posts) group by comment.post
    

    (鉴于我的数据访问层可能一次加载甚至50篇文章,在中设置50个参数长的是最佳的吗?)

    创建一个非映射实体属性,然后在所有涉及Post的存储库方法中手动填充它,并使用join:我希望避免这种情况。

    commentCount存储在数据库中,并使用触发器对其进行维护:这可能是一个选项,但它不是这个问题的重点(我不允许接触模式)

    什么是有效的解决方案?我正在使用Hibernate,但我更喜欢与实现无关的解决方案(尽管不会忽略特定于实现的选项)


  • 共有1个答案

    富凯风
    2023-03-14

    使用@Formula不会导致任何n1选择问题(不同于@PostLoad),因为指定的表达式是作为初始选择查询的一部分计算的。

    (实际上,您需要启用Hibernates字节码增强功能,以便能够延迟加载计算的@Formula属性:动态控制@Formula列的延迟/快速加载)

    因此,即使它是一个Hibernate特有的特性,需要本地SQL,@公式可能是实现这一点的一个好而简单的方法。

    如果相关子查询的性能缺陷变得显著,并且不需要计算属性,则可以另外创建仅包含所需属性的DTO投影。

     类似资料:
    • 我有以下问题: 包含带有字符串 、 或 C 的 。 带有的第二个 。 以及其他三列 、 和 (这些列也命名为 、 和 )。 因此 应获得 现在我想遍历每一行,并根据 中的条目将 中的整数分配给列 A、B 或 C。 如何实现此目的? < code>df.withColumn()我不能使用(或者至少我不知道为什么),对于< code>val df2 = df.map(x = 提前期待您的帮助和感谢!

    • 问题内容: JPA 2.0(Hibernate 4.2.4.Final/Spring 3.2.8.Release)/ Mysql 5.6 对于管理实体E w /自动生成的主键,例如 出于传统原因,foo需要等于:{id}:。例如,如果id为204,则foo将为“:204:”,因此在事务中发生这种情况是可行的 有没有一种更好的方法来计算值取决于生成的ID的派生列?没有上述技巧,即在持久化之后直接更新

    • 问题内容: 我有一个带有集合的类,它们是Hibernate管理的POJO。我也在使用 hbm.xml 文件映射我的实体。当用户转到管理屏幕时,我希望他将数据查看到表中,该表还将包含最近完成的工作。但是,只有访问可检测内容的详细信息页面,才能使用完整的修订集。 我的机会是显示最后的修订日期,该日期将作为每个实例的属性单独加载。所以我有这样的事情: detectable.hbm.xml 这是行不通的,

    • 问题内容: 我有一个带有集合的类,它们是Hibernate管理的POJO。我还使用 hbm.xml 文件映射了我的实体。当用户转到管理屏幕时,我希望他将数据查看到表中,该表还将包含最近完成的工作。但是,只有访问可检测内容的详细信息页面,才能使用完整的修订集。 我的机会是显示最后的修订日期,该日期将作为每个实例的属性单独加载。所以我有这样的事情: detectable.hbm.xml 这是行不通的,

    • ...但我得到: 我不知道如何应用这些信息。首先,我认为我需要为列表声明一些额外的映射(在同一个映射器类中),所以MapStruct知道如何像这样映射列表类型的每个字段: ...但我收到错误消息

    • 问题内容: 我的ViewValue类定义如下: 在我的代码中,我需要将ViewValue实例列表转换为包含来自相应ViewValue的id字段值的列表。 我用foreach循环来做: } 有没有更好的方法来解决这个问题? 问题答案: 编辑:此答案基于以下想法:您需要对代码中其他位置的不同实体和不同属性执行类似的操作。如果您 只需 要按ID将ViewValues列表转换为Longs列表,则请坚持使用