You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何结合自定义查询使用Hibernate Envers查询修订实体?

自定义查询Hibernate Envers已修订实体的关联问题

我想通过自定义查询查找已修订的实体,目的是完全控制实体加载时机,同时处理复杂关联查询。现有实体如下:

Product实体

@Data
@Entity
@Audited
@Table(name = "Product")
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private BigDecimal price;
    private Long orderId;
    @ManyToOne
    @JoinColumn(name = "ORDER_ID", insertable = false, updatable = false)
    private Order order;
}

Order实体

@Data
@Entity
@Audited
@Table(name = "Order")
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String text;
    private BigDecimal amount;

}

我尝试编写了以下查询代码,但返回的结果包含当前修订版本中不属于该关联的旧值:

public void findProductByOrderIdAndRevision(Long orderId, Long revisionFromOrder) {
    AuditReader auditReader = AuditReaderFactory.get(entityManager);

    return auditReader.createQuery().forEntitiesAtRevision(Product.class, revisionFromOrder)
            .traverseRelation("order", JoinType.INNER, "products", AuditEntity.id().eq(orderId))
            .getResultList();
}

请问有没有可行的解决方法?


解决方案

你的问题出在traverseRelation的用法上:当前写法关联了Order的修订数据,但没有确保Product在指定修订版本中的orderId确实匹配目标Order ID,而是直接关联Order的ID,导致会把历史上曾经关联过该Order的Product都查出来,哪怕在指定修订版本中Product已经不属于这个Order了。

有两种可行的解决方式:

方式一:直接基于Product的orderId字段查询

既然Product实体本身存储了orderId字段,完全可以直接针对这个字段在指定修订版本中做过滤,不需要关联Order实体,这种方式更高效且逻辑清晰:

public List<Product> findProductByOrderIdAndRevision(Long orderId, Long revision) {
    AuditReader auditReader = AuditReaderFactory.get(entityManager);
    
    return auditReader.createQuery()
            .forEntitiesAtRevision(Product.class, revision)
            .add(AuditEntity.property("orderId").eq(orderId))
            .getResultList();
}

方式二:正确关联Order的修订并匹配关联关系

如果必须通过关联Order实体来查询(比如需要同时过滤Order的其他属性),需要确保在指定修订版本中,Product和Order的关联关系是有效的,即Product的orderId等于Order的ID,并且两者都处于指定的修订版本:

public List<Product> findProductByOrderIdAndRevision(Long orderId, Long revision) {
    AuditReader auditReader = AuditReaderFactory.get(entityManager);
    
    return auditReader.createQuery()
            .forEntitiesAtRevision(Product.class, revision)
            .traverseRelation("order", JoinType.INNER)
                .add(AuditEntity.id().eq(orderId))
                .up()
            .getResultList();
}

这里的关键是去掉traverseRelation中的第三个参数(别名),通过up()回到Product的查询上下文,确保查询的是指定修订版本中与目标Order存在关联的Product,而不是历史上任何时候关联过的Product。


内容的提问来源于stack exchange,提问作者Akroma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 03:02:22