当前位置: 首页 > 知识库问答 >
问题:

比较JPA实体和DTO

宰修能
2023-03-14

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

基于若昂·迪亚斯的回答,方法4-继承。

优点/缺点

  • 方法1-一路坏
  • 方法2-使用接口支持组合而不是继承,但需要使用自定义方法名称的语义学(Business KeysMatch()
  • 方法3-不需要html" target="_blank">修改源代码
  • 方法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-添加到每个用户*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-仅使用基类的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();
            }
        }
    
  • 共有1个答案

    邰宇
    2023-03-14

    如果你有多个用户Dto,我会创建一个抽象的用户Dto,然后由所有具体的用户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());
        }
    }
    
     类似资料:
    • 问题内容: 将JPA 2与EclipseLink实现一起使用。 我正在尝试建立一个动态查询,该查询应该使我在给定日期后仍保留一些记录。 并且在这种情况下,API中仅有的两个方法可能对我有帮助。该警告是由日食引发的: 我可以想象我没有针对此问题采取正确的方法,但是我找不到任何可能的解决方案的提示或指示。 问题答案: 问题在于,使用基于字符串的API时,无法推断-Operation 的结果值的类型。例

    • 是否可以使用MockMCV比较实际的响应实体和从控制器返回的响应实体?

    • Javers v5.6.3 我有一个父实体,其中包含一系列子实体。当我区分两个父母列表,发现一个孩子有变化时,我需要知道哪个父母包含变化的孩子。 我的实体: 我想要区分的是: 为了简洁起见,切换到Groovy: 我是如何区分的: 输出: 我的问题是: 如何发现哪个父级包含子级/c1? 除了我有一个老板集合之外,这类似于应该检测薪酬变化()示例。使用该示例,给定具有不同下属的老板列表,如何找出的老板

    • 我知道这些接口用于对集合中的对象进行排序。但我怀疑这两者的真正区别。我读到的一个事实是,如果要比较两个对象而不使用当前对象,请使用Compariable(此)。 但我的问题是即使使用比较器,我们也会比较相同的对象类型。 这里真正的区别是什么。我很困惑。假设下面的例子, 如果我使用比较器,我会让一个类实现比较器,而不是这个。年龄,它有人。年龄那么这里有什么不同呢? 我不知道Collections.s

    • 我阅读了关于Lambda表达式的Java 8教程,但不太了解“引用特定类型的任意对象的实例方法”的方法引用示例 在同一教程中,有一个示例“引用特定对象的实例方法”,看起来像。 我可以看到这个工作,因为方法compareByName与Comparator.comparelambda(a, b)具有相同的签名- 现在“引用特定类型的任意对象的实例方法”示例使用String::compareToIgno

    • 我正在为一个项目使用OWLAPI,我需要比较两个本体之间的差异。这将忽略空节点,例如,我可以确定两个本体中是否存在相同的OWL限制。我不仅需要知道是否存在差异,而且需要找出那些差异是什么。OWLAPI和oz中是否存在这样的功能,有没有一个相对简单的方法来实现这一点?