首页 > 解决方案 > 如果 @GeneratedValue 包含来自另一个实体的外键,则无法使 @GeneratedValue 与 @IdClass 一起使用

问题描述

如果 @GeneratedValue 包含来自另一个实体的外键,我无法让 @GeneratedValue 与 @IdClass 一起使用。

所以我拥有的是一个看起来像这样的选项实体

   @Data
   @NoArgsConstructor
   @AllArgsConstructor
   @EqualsAndHashCode(callSuper = true)
   @Entity
   @Table(name = "options")
   public class Option extends UserDateAudit {
   
       @Id
       @GeneratedValue(strategy = GenerationType.IDENTITY)
       @Column(name = "option_id")
       private Long optionId;
   
       @NotBlank
       @Column(nullable = false)
       private String name;
   
       //one to many with optionValues entity
       @OneToMany(mappedBy = "option", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
       private Set<OptionValue> optionValues;
   
       @OneToMany(mappedBy = "option", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
       private Set<ProductOption> optionProducts;
   
   }

和一个 OptionValue 实体

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @EqualsAndHashCode(callSuper = true)
    @Entity
    @Table(name = "option_values")
    @IdClass(OptionValueId.class)
    public class OptionValue extends UserDateAudit {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "option_value_id")
        private Long optionValueId;
    
        @NotBlank
        @Column(nullable = false)
        private String valueName;
    
        @Id
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "option_id", referencedColumnName = "option_id")
        private Option option;
    
        @OneToMany(mappedBy = "optionValue", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
        private Set<VariantValue> variantValues;
    
    }
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class OptionValueId implements Serializable {
        private Long optionValueId;
        private Option option;
    }

我试着保存它

    public ResponseEntity<OptionValue> create(Long optionId, OptionValueCreateDto optionValueCreateDto) {
            Option option = optionRepository.findById(optionId).orElseThrow(
                    () -> new EntityNotFoundException("errors.option.notFound")
            );
            OptionValue optionValue = ObjectMapperUtils.map(optionValueCreateDto, OptionValue.class);
            optionValue.setOption(option);
            optionValue = optionValueRepository.save(optionValue);
            return new ResponseEntity<>(optionValue, HttpStatus.CREATED);
        }

但我得到以下异常

Resolved [org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'java.lang.Long' to required type 'com.ecommerce.product.model.Option' for property 'option'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.Long' to required type 'com.ecommerce.product.model.Option' for property 'option': no matching editors or conversion strategy found]

我无法弄清楚这里出了什么问题

我也试着让我的 IdClass 像这样

@Data
@AllArgsConstructor
@NoArgsConstructor
public class OptionValueId implements Serializable {
    @Column(name = "option_value_id")
    private Long optionValueId;
    @Column(name = "option_id")
    private Long option;
}

但它效果不佳并显示出类似的异常

编辑 1 事实证明它必须是一个复合键,因为这个复合键与另一个表中的相关使用,这导致了很多问题,以消除复合键提供的验证。

也许我应该首先澄清这一点。

标签: javaspringspring-boothibernatejpa

解决方案


该异常与 Spring Data 或 WebMvc 无法转换值有关。将生成的标识符与其他标识符混合是不可能的。为什么你仍然需要这两个值?IMO 在这里有一个复合 id 是没有意义的。只需使用这个:

@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "option_values")
@IdClass(OptionValueId.class)
public class OptionValue extends UserDateAudit {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "option_value_id")
    private Long optionValueId;

    @NotBlank
    @Column(nullable = false)
    private String valueName;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "option_id", referencedColumnName = "option_id")
    private Option option;

    @OneToMany(mappedBy = "optionValue", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private Set<VariantValue> variantValues;

}

推荐阅读