【问题标题】:Copying nested objects with references to each other复制相互引用的嵌套对象
【发布时间】:2017-12-21 11:39:45
【问题描述】:

我在数据库中有两个具有一对多关系的表。 当我获取表 User 时,我想将 User 中的数据(以及与 Vehicle 相关的数据)复制到另一个对象 UserDuplicate(和 VehicleDuplicate)。 我尝试使用 BeanUtils.copyProperties 但嵌套引用仍然引用旧对象。 我想知道复制嵌套对象的方法是什么。 谢谢。

import java.util.Set;


public class User {

    private Set<Vehicle> vehs = new HasHSet();

    public Set<Vehicle> getVehs() {
        return vehs;
    }

    public void setVehs(Set<Vehicle> vehs) {
        this.vehs = vehs;
    }
}

class Vehicle {

    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;

    }
}

class UserDuplicate {

    private Set<VehicleDuplicate> vehDup=new HasHSet();

    public Set<VehicleDuplicate> getVehDup() {
        return vehDup;
    }

    public void setVehDup(Set<VehicleDuplicate> vehDup) {
        this.vehDup = vehDup;
    }   
}

class VehicleDuplicate {

    private UserDuplicate userDup;

    public UserDuplicate getUserDup() {
        return userDup;
    }

    public void setUserDup(UserDuplicate userDup) {
        this.userDup = userDup;
    }   
}

【问题讨论】:

  • 我不明白为什么你有 VehicleDuplicateUserDuplicate - 它们与 Vehicle 和 @987654326 相同 @;他们可以达到什么目的?
  • 您必须创建一个递归方法来遍历对象的字段并调用克隆方法。此外,每个对象都必须实现/覆盖克隆方法才能做到这一点。 循环遍历 Java 类中的所有字段: stackoverflow.com/a/17095665/1715121
  • 我们有一个外部数据摄取到表中,我正在编写一个作业,在适当清理后将数据从一个表复制到另一个表。所以我正在将数据从暂存复制到应用程序表,或多或少相同的架构。

标签: java oracle


【解决方案1】:

我喜欢在这些情况下使用复制构造函数:

class UserDuplicate {

...

UserDuplicate(User user) {

...

    if (user.getVehs() != null) {
        vehDup = new HashSet<>();
        for (Vehicle v: user.getVehs()) {
            vehDup.add(new VehicleDuplicate(this, v));
        }
    }
}

...

class VehicleDuplicate {

...

VehicleDuplicate(UserDuplicate userDup, Vehicle veh) {
    this.userDup = userDup;

...

}

【讨论】:

  • 我做了更改并将构造函数称为:UserDuplicate u= new UserDuplicate(user);但我得到包含 vehileDuplicate 字段的 UserDuplicate 对象作为空数组列表。
  • @Aadil 那么它对你有什么建议?
  • @Aadil 我帮不了你:我的代码显然添加了与车辆一样多的 VehicleDuplicate。问题出在其他地方……
  • 谢谢。我将构造函数中的 vehDup 值设置为 this 对象,它起作用了.. this.setVehDup(vehDup) 谢谢
【解决方案2】:

一种方法是使用映射器将您需要的内容复制到复制的对象,这种方法可以减少您的代码占用...

例如,您可以使用jackson-databind

ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
UserDuplicate duplicated = mapper.readValue(mapper.writeValueAsString(source), UserDuplicate.class);
// set the correct duplicate user in the duplicated vehicule
duplicated.getVehDup().forEach(x -> x.setUserDup(duplicated));

这会将source 对象序列化为JSON,然后将其反序列化为duplicated 对象的实例。

因为您是说您的架构或多或少相同,所以您可以处理 Jackson 提供的注释,例如忽略某些字段。

static class User {

    @JsonIgnore // Allows to ignore attributes from stadging to production
    private String iDontWantToCopyThis = "blablabla";

    private Set<Vehicle> vehs;

    public Set<Vehicle> getVehs() {
        return vehs;
    }

    public void setVehs(Set<Vehicle> vehs) {
        this.vehs = vehs;
    }
}

这样做,iDontWantToCopyThis 字段不会被复制到复制的对象中。

因为您的Vehicle 包含对user 的引用,您需要使用@JsonIgnore 进行注释以避免反序列化期间的递归。

static class Vehicle {

    @JsonIgnore 
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;

    }
}

并且由于车辆集的名称与UserDuplicate 类不同,您必须使用注解@JsonProperty("vehs") 让映射器知道如何匹配数据。

 static class UserDuplicate {

    @JsonProperty("vehs") // need to specify the source name into the json used to load the user duplicated
    private Set<VehicleDuplicate> vehDup;

    public Set<VehicleDuplicate> getVehDup() {
        return vehDup;
    }

    public void setVehDup(Set<VehicleDuplicate> vehDup) {
        this.vehDup = vehDup;
    }   
}

如果您的数据转换过于复杂而无法仅通过注释进行处理,您还可以创建自定义序列化器或反序列化器...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多