2

我有类似的用例,如https://github.com/javers/javers/issues/98中所述。

在下面的代码中,当我更新依赖对象并提交 Employee bob 时,我希望从 JQL 查询中检索对依赖的更改QueryBuilder.byInstanceId(1L, Employee.class)

//update dependent's name ( WANT TO TRACK THIS FROM ROOT EMPLOYEE OBJECT)
Dependent aDep = bob.getDependentById(1L);
aDep.setName("Ramsey");
javers.commit("hr.manager", bob);

完整代码:

import lombok.Getter;
import lombok.Setter;
import org.javers.core.Javers;
import org.javers.core.JaversBuilder;
import org.javers.core.changelog.SimpleTextChangeLog;
import org.javers.core.diff.Change;
import org.javers.repository.jql.QueryBuilder;
import org.junit.Test;

import javax.persistence.Id;
import java.util.*;

public class JaversTests {

    @Test
    public void shouldPrintTextChangeLog() {
        // given:
        Javers javers = JaversBuilder.javers().build();

        //initial employee
        Employee bob = new Employee(1L, "Bob", 9_000, "Junior Developer");
        javers.commit("hr.manager", bob);

        // promoted
        bob.setPosition("Senior Developer");
        bob.setSalary(11_000);
        javers.commit("hr.director", bob);

        //add dependents
        bob.addDependents(new Dependent(1L, "Ram", "Son"), new Dependent(2L, "Kabita", "Daughter"));
        javers.commit("hr.manager", bob);

        //update dependent's name ( WANT TO TRACK THIS FROM ROOT EMPLOYEE OBJECT)
        Dependent aDep = bob.getDependentById(1L);
        aDep.setName("Ramsey");
        javers.commit("hr.manager", bob);

        List<Change> employeeChanges = javers.findChanges(
            QueryBuilder.byInstanceId(1L, Employee.class).withChildValueObjects().build());

        String employeeChangeLog = javers.processChangeList(employeeChanges, new SimpleTextChangeLog());

        System.out.println(employeeChangeLog);
    }
}

@Getter
@Setter
class Employee {
    @Id
    Long id;
    String name;
    double salary;
    String position;
    Set<Dependent> dependents = new HashSet<>();

    public Employee(Long id, String name, double salary, String position) {
        this.id = id;
        this.name = name;
        this.salary = salary;
        this.position = position;
    }

    void addDependents(Dependent... dependents) {
        getDependents().addAll(new LinkedList(Arrays.asList(dependents)));
    }

    Dependent getDependentById(Long id) {
        for (Dependent dep : getDependents()) {
            if (dep.getId() == id) {
                return dep;
            }
        }
        return null;
    }
}

@Setter
@Getter
class Dependent {

    @Id
    Long id;
    String name;
    String relation;

    public Dependent(Long id, String name, String relation) {
        this.id = id;
        this.name = name;
        this.relation = relation;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Dependent dependent = (Dependent) o;
        return Objects.equals(id, dependent.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

我得到以下输出。这缺少从属名称更改(从 Ram 到 Ramsey)。

commit 3.0, author: hr.manager, Oct 3, 2016 12:45:57 PM
  changed object: us.sdata.enroll.Employee/1
    set changed on 'dependents' property: [added:'us.sdata.enroll.Dependent/2', added:'us.sdata.enroll.Dependent/1']
commit 2.0, author: hr.director, Oct 3, 2016 12:45:57 PM
  changed object: us.sdata.enroll.Employee/1
    value changed on 'salary' property: '9000.0' -> '11000.0'
    value changed on 'position' property: 'Junior Developer' -> 'Senior Developer'

谢谢!

4

2 回答 2

1

在这种情况下没有干净的解决方案,因为 JaVers JQL 不支持实体连接。因此,没有简单的方法可以找到从实体 Y 的快照中引​​用的实体 X 的快照。我可以建议的是准备以 DDD 聚合(实体及其子 ValueObjects)形式形成的 DTO 对象并将这些 DTO 提交给 JaVers而不是您的原始域对象。我知道这不是一个优雅的解决方案。

于 2016-10-04T06:49:31.747 回答
1

withChildValueObjects()过滤器仅适用于子(依赖)ValueObjects,并且您将两个类都映射为实体(存在@Id ann)。

Employee由于和对象之间没有明确的父子关系Dependent,JaVers 对它们一视同仁。如果您映射Dependent为 ValueObject(删除 @Id 就足够了),您的测试将通过。

于 2016-10-03T22:09:27.163 回答