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

Javers对比实体与DTO问题求助:仅获新增/移除对象无法取值变更

解决Javers跨Entity/DTO对比只返回NewObject/ObjectRemoved的问题

嘿,我之前也碰到过类似的Javers跨类型对比的坑,咱们先搞清楚问题根源,再一步步解决它!

问题原因

Javers默认是通过类的全限定名 + 对象ID来识别“同一个对象”的。你的Entity和EntityDTO是完全不同的Java类,所以Javers会把它们当成两个毫无关系的对象——一边是要移除的旧对象,另一边是新增的新对象,自然就只返回ObjectRemoved和NewObject这两种变更了,而不会识别为属性变更。

解决方案

要让Javers把这两个不同类的对象当成同一个对象来对比,核心是让Javers识别它们的“身份一致性”,同时统一类型标识,下面给你两种可行的实现方式:

方式一:用@TypeName统一类型别名 + 手动指定全局ID

首先给两个类加上@TypeName注解,让Javers把它们归为同一种类型:

import org.javers.core.metamodel.annotation.TypeName;

@TypeName("Entity") // 统一类型别名
public class Entity {
    private ObjectId id;
    private String name;
    private String description;
    // getter/setter 省略
}

@TypeName("Entity") // 和Entity用同一个别名
public class EntityDTO {
    private String name;
    // getter/setter 省略
}

然后在对比的时候,手动给两个对象指定同一个GlobalId,告诉Javers它们是同一个实例:

// 初始化测试对象
Entity oldState = new Entity(new ObjectId("1"), "OldProductName", "OldDesc");
EntityDTO newState = new EntityDTO("NewProductName");

// 构建Javers实例
Javers javers = JaversBuilder.javers().build();

// 手动创建全局ID,关联两个对象的身份
GlobalId targetId = GlobalId.createFromInstanceId("Entity", oldState.getId());

// 执行对比,传入统一的GlobalId
Diff diff = javers.compare(oldState, newState, targetId, targetId);

// 现在就能拿到name属性的变更了
for (Change change : diff.getChanges()) {
    System.out.println(change);
}

方式二:自定义IdProvider(适合DTO无ID字段的场景)

如果你的DTO里没有id字段,可以通过自定义IdProvider来告诉Javers如何识别对象身份,同时配合TypeName统一类型:

// 自定义IdProvider,假设你通过业务规则确定DTO对应的Entity ID
class EntityDTOIdProvider implements IdProvider {
    @Override
    public Object getId(Object domainObject) {
        if (domainObject instanceof EntityDTO) {
            // 这里根据你的业务逻辑返回对应的Entity ID,比如从上下文或DTO的其他字段获取
            return "固定ID或业务推导的ID";
        }
        return IdProvider.DEFAULT.getId(domainObject);
    }
}

// 构建Javers时注册这个IdProvider和TypeName
Javers javers = JaversBuilder.javers()
        .withTypeNameMapping(new TypeNameMapping(Entity.class, "Entity"))
        .withTypeNameMapping(new TypeNameMapping(EntityDTO.class, "Entity"))
        .withIdProvider(new EntityDTOIdProvider())
        .build();

// 直接对比即可,Javers会自动识别身份
Diff diff = javers.compare(oldState, newState);

额外提示

  • Javers只会对比两个对象共同拥有的属性,比如description只在Entity里有,DTO里没有,对比时会自动忽略这个属性,不会标记为移除。
  • 如果只想关注特定属性,可以用DiffBuilder来过滤:
Diff diff = DiffBuilder.compare(oldState, newState)
        .withJavers(javers)
        .includeProperty("name")
        .build();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:34:16