我使用Spring Boot 2,并且我的某些实体具有复合键
当我尝试保存实体时,出现此错误
无法转换请求元素: org.springframework.beans.ConversionNotSupportedException:失败 将类型'java.lang.Integer'的属性值转换为所需的类型 “ com.lcm.model.SamplingsPK”用于属性“ sampling”;嵌套异常 是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;
}
}
编辑
当我通过采样时保存样品没问题
答案 0 :(得分:0)
此问题的跟踪源为https://jira.spring.io/browse/DATAJPA-1391,与@Id @ManyToOne
中使用Samples
有关。作为一种解决方法,您可以尝试为Samplings
创建一个构造函数,该构造函数使用其两个主键,或者可以使用一个java.lang.Integer
?这适用于单个级别的组合主键,但是如果您具有多个级别,则可能不起作用。
在year
中还有SamplingsPK
被键入为int
而不是Integer
。这可能会导致PK识别出现问题,因为需要特别考虑才能处理可自动装箱的原始类,并且我怀疑它是否已被考虑。
答案 1 :(得分:0)
问题在于,由于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);
}
}