【问题标题】:Why entity objects are not equal if I get one of that object with another fetched object that has collection elements although they should be?如果我得到一个对象与另一个具有集合元素的获取对象,为什么实体对象不相等,尽管它们应该是?
【发布时间】:2022-01-15 18:37:36
【问题描述】:

我有 3 个相互关联的实体类

TestClassParent:

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(of = "email")
@Inheritance(strategy = InheritanceType.JOINED)
public class TestClassParent {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String email;
}

TestClassChild:

@Entity
@Data
@EqualsAndHashCode(callSuper = true)
public class TestClassChild extends TestClassParent{

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "test_collection_id")
    private TestChildCollection testChildCollection;
}

TestChildCollection:

@Entity
@Data
@EqualsAndHashCode(of ="id")
@AllArgsConstructor
@NoArgsConstructor
public class TestChildCollection {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @OneToMany(mappedBy = "testChildCollection",cascade = CascadeType.ALL,fetch = FetchType.EAGER)
    private Set<TestClassChild> testClassChildSet;
}

目前我的数据库是这样的:

关系:

对象的平等是通过比较他们的电子邮件来完成的

我有测试这个案例的代码:

@SpringBootApplication
@AllArgsConstructor
public class DemoApplication {
    private final TestClassChildRepository testClassRepository;
    private final TestChildCollectionRepository testChildCollectionRepository;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
    @Bean
    public ApplicationRunner applicationRunner() {
        return args -> {
            TestClassChild testClassChild = testClassRepository.findById(1L).get();
            TestClassChild testClass1 = new TestClassChild();
            testClass1.setId(testClassChild.getId());
            testClass1.setEmail(new String("newTestEmail2"));
            System.out.println(testClass1.equals(testClassChild));
        };
    }

}

比较这些对象我会弄错

结果是:

我寻找调试并看到,第一个实例在电子邮件中有哈希码,而另一个没有 第一个:

第二个:

【问题讨论】:

  • TestClassChild 类中的字段testChildCollection 用于equals() 方法,看来您需要@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = true) 而不是@EqualsAndHashCode(callSuper = true)。顺便说一句,我确实认为以这种方式覆盖 equals/hashCode 方法不是一个好主意,请考虑以下内容:从技术上讲,JPA 记录表示 DB 行,相等的记录是否必须指向同一行?

标签: java hibernate set equals hashcode


【解决方案1】:

testClassRepository.findById(1L).get(); 返回一个带有testChildCollection 的对象。当您生成新的TestClassChild 时,您设置了 id 和电子邮件,但没有设置集合,但在您的示例中,Lombok 还使用 testChildCollection 来计算 equals/hashCode。

在使用继承时,我通常会尽量避免使用@Data,因为这样很容易忘记实际生成 equals/hashCode 的方式。

@Entity
@Getter
@Setter
@ToString(callSuper = true) // Only if you really need a toString implementation that also prints your collection.
public class TestClassChild extends TestClassParent

在没有 hashCode/equals 生成的情况下也会这样做。

【讨论】:

    【解决方案2】:

    问题是您的TestClassChild equals() 方法还包括对其testChildCollection 属性的检查。变量testClassChild 的属性为not null,但testClass1 的属性为null。因此调用testClass1.equals(testClassChild) 将始终是false

    如果您只想依赖超类equals() 实现,则必须排除testClassChild,如下所示:

    @Entity
    @Data
    @EqualsAndHashCode(callSuper = true)
    public class TestClassChild extends TestClassParent{
    
        @EqualsAndHashCode.Exclude
        @ManyToOne(fetch = FetchType.EAGER)
        @JoinColumn(name = "test_collection_id")
        private TestChildCollection testChildCollection;
    }
    

    【讨论】:

      猜你喜欢
      • 2011-12-22
      • 1970-01-01
      • 2021-08-11
      • 2020-05-07
      • 2018-09-02
      • 2012-01-22
      • 1970-01-01
      相关资源
      最近更新 更多