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

如何在PrePersistenceHook保存更新前获取ProductModel旧值?

在SAP Commerce(Hybris)PrePersistenceHook中正确获取ProductModel旧值的方案

问题根源

Hybris的会话缓存(一级缓存)会复用同一PK的模型实例,直接通过productService获取或调用modelService.refresh()会导致新旧模型共享引用,无法正确对比值。以下是两种可靠的解决方案:


方法一:通过FlexibleSearch绕过缓存获取数据库原始值

直接用FlexibleSearch从数据库查询,再分离实例避免上下文干扰,确保拿到的是未被修改的旧值。

public Optional<ItemModel> execute(ItemModel item, PersistenceContext context) {
    if (item instanceof ProductModel productToInsert) {
        // 编写查询语句,指定需要对比的属性
        final String query = "SELECT {p.pk}, {p.name}, {p.description} FROM {Product AS p} WHERE {p.code} = ?code";
        final FlexibleSearchQuery flexibleSearchQuery = new FlexibleSearchQuery(query);
        flexibleSearchQuery.addQueryParameter("code", productToInsert.getCode());
        // 强制绕过缓存,直接从数据库读取
        flexibleSearchQuery.setCacheable(false);
        
        final SearchResult<ProductModel> result = flexibleSearchService.search(flexibleSearchQuery);
        if (!result.getResult().isEmpty()) {
            ProductModel oldProduct = result.getResult().get(0);
            // 分离实例,避免与当前待保存模型共享引用
            modelService.detach(oldProduct);
            
            // 对比新旧值
            String newName = cleanNameOrDesc(productToInsert.getName());
            String oldName = oldProduct.getName();
            String newDesc = cleanNameOrDesc(productToInsert.getDescription());
            String oldDesc = oldProduct.getDescription();
            
            if ((StringUtils.isNotBlank(newName) && newName.equals(oldName))
                || (StringUtils.isNotBlank(newDesc) && newDesc.equals(oldDesc))) {
                productToInsert.setApprovalStatus(ArticleApprovalStatus.CHECK);
            }
        }
    }
    return Optional.of(item);
}

方法二:利用PersistenceContext获取原始值(性能最优)

Hybris的PersistenceContext内置了当前模型的变更属性原始值,无需额外查询数据库,仅返回被修改过的属性旧值。

public Optional<ItemModel> execute(ItemModel item, PersistenceContext context) {
    if (item instanceof ProductModel productToInsert) {
        // 获取属性旧值映射,key为属性名,value为数据库原始值
        Map<String, Object> originalValues = context.getOriginalValues();
        
        if (originalValues != null) {
            String oldName = (String) originalValues.get("name");
            String oldDesc = (String) originalValues.get("description");
            
            String newName = cleanNameOrDesc(productToInsert.getName());
            String newDesc = cleanNameOrDesc(productToInsert.getDescription());
            
            if ((StringUtils.isNotBlank(newName) && newName.equals(oldName))
                || (StringUtils.isNotBlank(newDesc) && newDesc.equals(oldDesc))) {
                productToInsert.setApprovalStatus(ArticleApprovalStatus.CHECK);
            }
        }
    }
    return Optional.of(item);
}

方案对比

  • 方法一:适合需要完整旧模型或对比大量属性的场景,缺点是需要额外数据库查询。
  • 方法二:性能最优,仅获取变更属性的旧值,适合只关注修改字段的场景。

之前尝试方案的问题说明

  1. productService.getProductForCode返回新值:会话缓存已保存修改后的模型实例,直接获取会复用同一对象。
  2. modelService.refresh(oldProduct)导致实例同步:新旧模型是同一引用,refresh会重置实例为数据库值,覆盖当前待保存的修改。
  3. 分离后赋值报错:不能将分离实例赋值给当前待保存的item,分离实例仅用于读取旧值,不可替换上下文对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 15:41:15