比较 JPA 实体和 DTO

Compare JPA Entity and DTO

我需要一种标准方法来将 JPA 实体与其 DTO 进行比较,并确定它们是否代表相同的业务对象。我可以想到三种方法,每个 DTO 上的自定义方法,带有静态方法或比较器的接口。

基于 João Dias 的答案,方法 4 - 继承。

Pros/Cons

任何其他 pros/cons 方法或对其他方法的建议?

最终,我选择了方法二(Interface)。继承方法显示出希望,但作为 JPA 实体的 classes 之一使映射比我想要的更复杂。

感谢阅读和思考我的问题!

背景

实体

DTO(完整)

DTO(有限)

方法 1 - 添加到每个 User*Dto

的自定义方法
    boolean businessKeysMatch(UserEntity entity) {
        if((this.getBusinessKey1() == entity.getBusinessKey1()) && (this.getBusinessKey2() == entity.getBusinessKey2()))
            return true;
        return false;
    }

方法 2 - 将静态方法添加到公共接口

    interface UserKeys {
        Long getBusinessKey1();
        Long getBusinessKey2();
        static boolean businessKeysMatch(UserKeys o1, UserKeys o2) {
            if((o1.getBusinessKey1() == o2.getBusinessKey1()) && (o1.getBusinessKey2() == o2.getBusinessKey2()))
                return true;
            return false;
        }
    }

    class UserEntity implements UserKeys {
        // no other changes
    }

    class UserDto implements UserKeys {
        // no other changes
    }

    class UserEntity implements UserKeys {
        // no other changes
    }

方法 3 - 比较器

    interface UserBusinessKey {
        Long getBusinessKey1();
        Long getBusinessKey2();
    }

    class UserDto implements UserCompare {
        // no other changes
    }

    class UserEntity implements UserCompare {
        // no other changes
    }

    class UserCompare implements Comparator<UserBusinessKey> {
        public int compare(UserBusinessKey o1, UserBusinessKey o2) {
            int key1Compare = o1.getBusinessKey1().compareTo(o2.getBusinessKey1());

            if (key1Compare == 0) 
                return o1.getBusinessKey2().compareTo(o2.getBusinessKey2());
            return key1Compare;
        }
    }

方法 4 - 仅继承基数 class 的 equals/hashcode

    @SuperBuilder
    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    abstract class UserBase {
        @NotNull
        Long businessKey1;
        @NotNull
        Long businessKey2;
        // lombok generates a standard equals() / hashcode() pair
    }

    @SuperBuilder
    @Getter
    @Setter
    @ToString
    @Entity
    @Table(uniqueConstraints = { @UniqueConstraint(columnNames = { "businessKey1", "businessKey2" }) })
    class UserEntity extends UserBase {
        @Id
        Long id;
        String name;
        Integer age;
        String password;
        String refreshToken;
        String SSN;
        
        // handcoded equals/hashcode that only call super
        @Override
        public boolean equals(Object obj) {
            return super.equals(obj);
        }

        @Override
        public int hashCode() {
            return super.hashCode();
        }
    }

    @SuperBuilder
    @Getter
    @Setter
    @ToString
    class UserDto extends UserBase {
        String name;
        String address;
        Integer age;
        
        // handcoded equals/hashcode that only call super
        @Override
        public boolean equals(Object obj) {
            return super.equals(obj);
        }

        @Override
        public int hashCode() {
            return super.hashCode();
        }
    }

如果您有多个 User*Dto,我会创建一个抽象 AbstractUserDto,然后由所有具体的用户 DTO 对其进行扩展。您可以在那里放置您在方法 1 中显示的方法(这样您就不会一遍又一遍地复制相同的代码):

@Data
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public abstract class AbstractUserDto {
    @EqualsAndHashCode.Include
    @NotNull
    Long businessKey1;
    
    @EqualsAndHashCode.Include
    @NotNull
    Long businessKey2;
    
    String name;

    public final boolean businessKeysMatch() {
        return (this.getBusinessKey1() == entity.getBusinessKey1()) && (this.getBusinessKey2() == entity.getBusinessKey2());
    }
}