【问题标题】:Compare JPA Entity and DTO比较 JPA 实体和 DTO
【发布时间】:2022-01-04 23:14:32
【问题描述】:

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

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

优点/缺点

  • 方法 1 - 一直都很糟糕
  • 方法 2 - 使用接口来支持组合而不是继承,但需要使用自定义方法名称的语义 (businessKeysMatch())
  • 方法 3 - 不需要修改源代码
  • 方法 4 - 简化语义,因为它使用标准 equals(),但需要“样板文件 equals()/hashcode()

这些方法的任何其他优点/缺点或对其他方法的建议?

最后,我选择了使用方法 2(接口)。继承方法显示出了希望,但是作为 JPA 实体的类之一使映射比我想要的更复杂。

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

背景

实体

  • 一个数据库键

  • 在 ORM 和确定相等性的数据库中唯一强制执行的业务密钥 (equals()/hashcode())

  • 公共属性(姓名、地址、年龄等)

  • 非公开/机密属性(密码、刷新令牌、SSN 等)

      @Data
      @EqualsAndHashCode(onlyExplicitlyIncluded = true)
      @Entity
      @Table(uniqueConstraints = { @UniqueConstraint(columnNames = { "businessKey1", "businessKey2" }) })
      class UserEntity {
          @Id
          Long id;
          @NotNull
          @EqualsAndHashCode.Include
          Long businessKey1;
          @NotNull
          @EqualsAndHashCode.Include
          Long businessKey2;
          String name;
          Integer age;
          String password;
          String refreshToken;
          String SSN;
      }
    

DTO(完整)

  • 确定相等性的业务密钥 (equals()/hashcode())

  • 公共属性(姓名、地址、年龄等)

      @Data
      @EqualsAndHashCode(onlyExplicitlyIncluded = true)
      class UserDto {
          @EqualsAndHashCode.Include
          @NotNull
          Long businessKey1;
          @EqualsAndHashCode.Include
          @NotNull
          Long businessKey2;
          String name;
          String address;
          Integer age;
      }
    

DTO(有限)

  • 确定相等性的业务密钥 (equals()/hashcode())

  • 选定的公共属性(名称)

      @Data
      @EqualsAndHashCode(onlyExplicitlyIncluded = true)
      class UserNameDto {
          @EqualsAndHashCode.Include
          @NotNull
          Long businessKey1;
          @EqualsAndHashCode.Include
          @NotNull
          Long businessKey2;
          String name;
      }
    

方法 1 - 添加到每个 User*Dto 的自定义方法

    boolean businessKeysMatch(UserEntity entity) {
        if((this.getBusinessKey1() == entity.getBusinessKey1()) && (this.getBusinessKey2() == entity.getBusinessKey2()))
            return true;
        return false;
    }

方法二 - 将静态方法添加到通用接口

    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 - 仅使用基类的 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();
        }
    }

【问题讨论】:

    标签: java jpa spring-data-jpa lombok


    【解决方案1】:

    如果您有多个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());
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-16
      • 1970-01-01
      • 1970-01-01
      • 2011-08-16
      • 1970-01-01
      • 1970-01-01
      • 2012-03-15
      • 1970-01-01
      相关资源
      最近更新 更多