如何结合自定义查询使用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
相关产品推荐
相关产品推荐

