首页 > 解决方案 > 选择具有知情自然 ID 的实体,而不是尝试插入(JPA 和 SpringBoot)

问题描述

所以基本上我有以下需求。一个人将通过 Rest Controller 发布一个名为“Expense Report”的实体。

该实体有一个 Country 字段,它实际上是与另一个实体的关联。

@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "EXPENSE_REPORTS")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ExpenseReport extends BaseEntity {

    @Column(name = "TRIP_DESCRIPTION", nullable = false)
    private String tripDescription;

    @Column(name = "JUSTIFICATION")
    private String justification;

    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumn(name = "COUNTRY_ID")
    private Country country;

    @Column(name = "TRIP_START_DATE")
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
    @JsonDeserialize(using = LocalDateDeserializer.class)
    @JsonSerialize(using = LocalDateSerializer.class)
    private LocalDate tripStartDate;

    @Column(name = "TRIP_END_DATE")
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
    @JsonDeserialize(using = LocalDateDeserializer.class)
    @JsonSerialize(using = LocalDateSerializer.class)
    private LocalDate tripEndDate;

    @Column(name = "TOTAL_AMOUNT")
    private BigDecimal totalAmount;

    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumn(name="USER_ID")
    private User user;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumn(name="EXPENSE_ITEM_ID")
    private Set<ExpenseItem> expenses;

}
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "COUNTRIES")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Country extends BaseEntity {

    @Column(name = "NAME")
    @NaturalId
    private String name;
}

我想要检查的是,调用者是否有可能只是发送国家的自然 ID(在这种情况下是名称)和 JPA 而不是尝试插入这个国家,他会找到具有相同名称的国家并关联它。

所以,而不是发送这个帖子:

{
    "tripDescription": "Some trip description...",
    "justification": "Some justification...",
    "country": {
      "id": 12345
    }
}

他发送这个:

{
    "tripDescription": "Some trip description...",
    "justification": "Some justification...",
    "country": {
      "name": "BR"
    }
}

我可以想象如何在存储库实现中执行此操作,但我想知道在 JPA 中是否有自动执行此操作的功能。

提前致谢。

标签: javaspring-bootjpaspring-data-jpa

解决方案


使用如下关联,而不是 COUNTRIES.COUNTRY_ID 使用 COUNTRIES.NAME

public class ExpenseReport extends BaseEntity {

    @Column(name = "TRIP_DESCRIPTION", nullable = false)
    private String tripDescription;

    @Column(name = "JUSTIFICATION")
    private String justification;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = “NAME”,referencedColumnName = "name" ) //Do not use COUNTRY_ID
    private Country country;
….
}
public class Country extends BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "NAME”,nullable = false, updatable = false, unique = true)
    @NaturalId(mutable = false)
    private String name;

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }

        if (!(o instanceof Country)) {
            return false;
        }

        Product naturalIdCountry = (Country) o;
        return Objects.equals(getName(), naturalIdCountry.getName());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getName());
    }
}

推荐阅读