如果根对象中的简单属性发生更改,则JaVers会检测子级中的更改

我使用Kotlin,我试图用JaVers比较两个复杂的对象(多个周期)。 这些对象使用多个Id-属性。 因此,我创建了Id-Classes,为每个类都有一个Id-Property。 在Id-Classes中,我也使用对根对象的引用,因为我需要使用它们来为我的数据库创建主键。

当我比较两个对象和根对象中的一个更改时,JaVers应该只列出一个ValueChange。 但是相反,JaVers发现了5个改变(NewObject-child,ObjectRemoved-child,ReferenceChanged-child,ListChange-root,ValueChanged-root)。 试图解决这个问题,我更新了我的equals和hashCode方法的子对象来检查根对象的id而不是根对象本身当计算相等==> root1.childList == root2.childList返回true 。 任何想法,我可以教JaVers没有任何儿童对象已经改变?

League.kt – 根对象

 @Entity data class League(@EmbeddedId val leagueId: LeagueId? = null, var name: String? = null, var region: String? = null, @OneToMany(cascade = [CascadeType.ALL], orphanRemoval = true) var groups: List? = null, @OneToMany(cascade = [CascadeType.ALL], orphanRemoval = true) var matchDays: List? = null) : Serializable { override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as League if (leagueId != other.leagueId) return false if (name != other.name) return false if (region != other.region) return false if (groups?.map { it.teamGroupId }?.toSet() != other.groups?.map { it.teamGroupId }?.toSet()) return false if (matchDays?.map { it.matchDayId }?.toSet() != other.matchDays?.map { it.matchDayId }?.toSet()) return false return true } override fun hashCode(): Int { var result = leagueId?.hashCode() ?: 0 result = 31 * result + (name?.hashCode() ?: 0) result = 31 * result + (region?.hashCode() ?: 0) result = 31 * result + (groups?.map { it.teamGroupId }?.toSet()?.hashCode() ?: 0) result = 31 * result + (matchDays?.map { it.matchDayId }?.toSet()?.hashCode() ?: 0) return result } } 

LeagueId.kt – 根对象ID

 data class LeagueId(val season : String? = null, val abb : String? = null) : Serializable { override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as LeagueId if (season != other.season) return false if (abb != other.abb) return false return true } override fun hashCode(): Int { var result = season?.hashCode() ?: 0 result = 31 * result + (abb?.hashCode() ?: 0) return result } } 

TeamGroup.kt – 子对象

 @Entity data class TeamGroup(@EmbeddedId val teamGroupId: TeamGroupId? = null, val name: String? = null, val mode: String? = null, val tableMode: Int? = null, @OneToMany(mappedBy = "group", cascade = [CascadeType.ALL], orphanRemoval = true) var teams: List? = null, @OneToMany(mappedBy = "group", cascade = [CascadeType.ALL], orphanRemoval = true) var matches: List? = null, var remarks: String? = null, @OneToMany(cascade = [CascadeType.ALL], orphanRemoval = true) var rows: List? = null) : Serializable { override fun toString(): String { return "TeamGroup(id=${teamGroupId?.id}, nr=${teamGroupId?.nr}, name=$name, mode=$mode, " + "tableMode=$tableMode, teams=$teams, matches=$matches, remarks=$remarks, rows=$rows, " + "league=${teamGroupId?.league?.leagueId?.season}-${teamGroupId?.league?.leagueId?.abb})" } override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as TeamGroup if (teamGroupId != other.teamGroupId) return false if (name != other.name) return false if (mode != other.mode) return false if (tableMode != other.tableMode) return false if (teams?.map{it.id}?.toSet() != other.teams?.map{it.id}?.toSet()) return false if (matches?.map{it.matchId}?.toSet() != other.matches?.map{it.matchId}?.toSet()) return false if (remarks != other.remarks) return false if (rows?.map{it.rowId}?.toSet() != other.rows?.map{it.rowId}?.toSet()) return false return true } override fun hashCode(): Int { var result = teamGroupId?.hashCode() ?: 0 result = 31 * result + (name?.hashCode() ?: 0) result = 31 * result + (mode?.hashCode() ?: 0) result = 31 * result + (tableMode ?: 0) result = 31 * result + (teams?.map{it.id}?.toSet()?.hashCode() ?: 0) result = 31 * result + (matches?.map{it.matchId}?.toSet()?.hashCode() ?: 0) result = 31 * result + (remarks?.hashCode() ?: 0) result = 31 * result + (rows?.map{it.rowId}?.toSet()?.hashCode() ?: 0) return result } } 

TeamGroupId.kt – 子对象ID

 data class TeamGroupId(@ManyToOne val league: League? = null, val id : Int? = null, val nr : Int? = null) : Serializable { override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as TeamGroupId if (league?.leagueId != other.league?.leagueId) return false if (id != other.id) return false if (nr != other.nr) return false return true } override fun hashCode(): Int { var result = league?.leagueId?.hashCode() ?: 0 result = 31 * result + (id ?: 0) result = 31 * result + (nr ?: 0) return result } } 

更新

你可以在github的回购中find我所有的源代码: https : //github.com/alexander-schmidt/ihh/tree/comparison 。

问题是在子对象的id内对根对象的引用。 如果我从id中移除这个引用并移动到对象本身,JaVers只能检测到一个变化。 由于我的数据模型,我不知道是否可以删除每个id对象中的这个引用。 @DiffIgnore不在Id属性中工作,因为它是作为ValueObject处理的。

该问题是由您的实体的InstanceId值错误造成的。 由于您具有复杂的对象作为实体ID,JaVers使用reflectToString reflectiveToString()函数来创建ID的字符串表示forms。 在你的情况下,它会产生非常糟糕的结果,因为你有循环(ID有一个拥有实体的参考)。

幸运的是,您可以使用JaversBuider.registerValueWithCustomToString()注册自定义的toString()函数,例如:

 @TypeName("Entity") class Entity { @Id Point id String data } class Point { double x double y String myToString() { "("+ (int)x +"," +(int)y + ")" } } def "should use custom toString function for complex Id"(){ given: Entity entity = new Entity(id: new Point(x: 1/3, y: 4/3)) when: "default reflectiveToString function" def javers = JaversBuilder.javers() .build() GlobalId id = javers.getTypeMapping(Entity).createIdFromInstance(entity) then: id.value() == "Entity/0.3333333333,1.3333333333" when: "custom toString function" javers = JaversBuilder.javers() .registerValueWithCustomToString(Point, {it.myToString()}) .build() id = javers.getTypeMapping(Entity).createIdFromInstance(entity) then: id.value() == "Entity/(0,1)" } 

另请参阅关于实体ID的更新文档https://javers.org/documentation/domain-configuration/#entity-id