【问题标题】:Saving entity with composite key get ConversionNotSupportedException使用复合键保存实体获取 ConversionNotSupportedException
【发布时间】:2019-01-11 21:51:35
【问题描述】:

我使用 spring boot 2,我的一些实体有复合键

当我尝试保存实体时,出现此错误

转换请求元素失败: org.springframework.beans.ConversionNotSupportedException:失败 将类型“java.lang.Integer”的属性值转换为所需类型 'com.lcm.model.SamplingsPK' 用于属性“采样”;嵌套异常 是 java.lang.IllegalStateException:无法转换类型的值 'java.lang.Integer' 到所需的类型 'com.lcm.model.SamplingsPK' 属性“采样”:未找到匹配的编辑器或转换策略

我用那个方法得到了我的实体

public Samples findById(Integer id, int year, String sampleLetter) {
    Optional<Samples> optSamples = samplesRepository.findById(new SamplesPK(new SamplingsPK(year, id), sampleLetter));

    if (optSamples.isPresent()) {
        return optSamples.get();
    }

    return null;
}


Samples samples = samplesService.findById(idSeq, year, samplesLetter);

Compressions compressionTest = null;

if (samples.getTestSamples().getAbsorptionTest() != null) {
    compressionTest = samples.getTestSamples().getCompressionTest();
} else {
    compressionTest = new Compressions();
}

samplesService.save(samples);

我的实体

@Entity
@IdClass(SamplesPK.class)
public class Samples extends BaseEntity{
    @Id
    private String sampleLetter;

    @Embedded
    private TestSamples testSamples;

    @Id
    @ManyToOne(optional=false)
    @JoinColumns({
        @JoinColumn(name = "sampling_id", referencedColumnName = "id"),
        @JoinColumn(name = "sampling_year", referencedColumnName = "year")})
    private Samplings sampling;
}

@Entity
@IdClass(SamplingsPK.class)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Samplings {
    @Id
    private Integer year;

    @Id
    @GeneratedValue
    private Integer id;

    @OneToMany(mappedBy = "sampling", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Samples> samples = new ArrayList<>();
}

public class SamplingsPK implements Serializable {

    private int year;

    private Integer id;

    public SamplingsPK(int year, Integer id) {
        this.id = id;
        this.year = year;
    }
}

public class SamplesPK implements Serializable {

    private SamplingsPK sampling;

    private String sampleLetter;

    public SamplesPK(SamplingsPK sampling, String sampleLetter) {
        this.sampling = sampling;
        this.sampleLetter = sampleLetter;
    }
}

编辑

保存样本没问题,当我通过采样时

【问题讨论】:

  • 遇到同样的问题。我发现如果您直接使用 EntityManager,您可以正确地保留实体。同时,我打开了jira.spring.io/browse/DATAJPA-1391
  • 不确定,因为我可以创建采样和采样...但可以通过压缩保存采样...

标签: spring hibernate jpa spring-data-jpa spring-data


【解决方案1】:

我也注意到了这一点。它不会发生在我的 Windows IDE 上,但会发生在 Azure 构建服务器上

我在org.springframework.data:spring-data-jpa:jar:2.4.5:compile

我将 BOM 升级到 &lt;spring-data-bom.version&gt;2020.0.15&lt;/spring-data-bom.version&gt;,所以我有 org.springframework.data:spring-data-jpa:jar:2.4.15:compile

一旦我这样做了,它就开始正常工作了。

【讨论】:

    【解决方案2】:

    问题在于,由于 ID 是手动设置的,并且这些实体上没有 @Version 属性,因此 Spring Data 无法知道实体是全新的还是现有的。在这种情况下,它决定它是一个现有实体并尝试使用merge 而不是persist。这显然是一个错误的结论。

    您可以阅读更多有关 Spring Data 如何确定实体是否为新实体的信息here

    我发现的最佳解决方案是始终让具有手动设置 ID 的实体类实现 Persistable interface。这解决了问题。对于任何此类情况,我都会为自己制定这条规则。大多数时候我不必实现Persistable,因为我的实体要么有一个自动生成的密钥,要么我的实体使用“@Version”注释。但这是特例。

    因此,根据 Spring 官方文档中的建议,例如 Samplings 类将变为:

    @Entity
    @IdClass(SamplingsPK.class)
    @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
    public class Samplings implements Persistable<SamplingsPK> {
        @Transient
        private boolean isNew = true; 
    
        @Id
        private Integer year;
    
        @Id
        @GeneratedValue
        private Integer id;
    
        @OneToMany(mappedBy = "sampling", cascade = CascadeType.ALL, orphanRemoval = true)
        private List<Samples> samples = new ArrayList<>();
    
        @Override
        public boolean isNew() {
            return isNew; 
        }
    
        @PrePersist 
        @PostLoad
        void markNotNew() {
            this.isNew = false;
        }
    
        @Override
        public SamplingsPK getId() {
            return new SamplingsPK(year, id);
        }
    }
    

    【讨论】:

      【解决方案3】:

      此问题在 https://jira.spring.io/browse/DATAJPA-1391 进行跟踪,并且与在 Samples 中使用 @Id @ManyToOne 有关。作为一种解决方法,您可以尝试为 Samplings 创建一个构造函数,该构造函数接受它的两个主键,或者一个接受 java.lang.Integer 的主键?这适用于单级复合主键,但如果您有多个级别,它可能不起作用。

      SamplingsPK 中的 year 也输入为 int 而不是 Integer。这可能会导致 PK 识别出现问题,因为处理可自动装箱的原始类需要特别考虑,我怀疑是否考虑过。

      【讨论】:

        猜你喜欢
        • 2017-05-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多