尝试使用@IdClass主键保存JPA实体时出现奇怪的错误。使用测试并将实体直接保存到存储库可以在不涉及事务的情况下工作,但在通过服务时会抛出错误。
org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'xxx.yyy.model.entity.TournamentEntity_$$_jvstffa_0' to required type 'java.lang.String' for property 'tournament'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'xxx.yyy.model.entity.TournamentEntity_$$_jvstffa_0' to required type 'java.lang.String' for property 'tournament': no matching editors or conversion strategy found
at org.springframework.beans.AbstractNestablePropertyAccessor.convertIfNecessary(AbstractNestablePropertyAccessor.java:590)
at org.springframework.beans.AbstractNestablePropertyAccessor.convertForProperty(AbstractNestablePropertyAccessor.java:604)
at org.springframework.beans.AbstractNestablePropertyAccessor.processLocalProperty(AbstractNestablePropertyAccessor.java:453)
at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:278)
at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:246)
at org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper.setPropertyValue(DirectFieldAccessFallbackBeanWrapper.java:75)
at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation$IdentifierDerivingDirectFieldAccessFallbackBeanWrapper.setPropertyValue(JpaMetamodelEntityInformation.java:340)
at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.getId(JpaMetamodelEntityInformation.java:166)
at org.springframework.data.repository.core.support.AbstractEntityInformation.isNew(AbstractEntityInformation.java:42)
at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.isNew(JpaMetamodelEntityInformation.java:232)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:489)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:377)
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:629)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:593)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:578)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy114.save(Unknown Source)
at xxx.yyy.service.TournamentService.createParty(TournamentService.java:104)
我的TournamentEntity课程如下所示:
@Entity
@Table(name = "TOURNAMENT")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TournamentEntity {
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
@Column(name = "ID")
private String id;
@OneToMany(mappedBy = "tournament", cascade = ALL)
List<PartyEntity> parties;
}
我的PartyEntity类看起来像是这样的问题:
@Entity
@Table(name = "PARTY")
@ToString(exclude = "tournament")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@IdClass(PartyId.class)
public class PartyEntity {
@Id
@ManyToOne
@JoinColumn(name = "TOURNAMENT_ID", referencedColumnName = "ID", insertable = false, updatable = false)
private TournamentEntity tournament;
@Id
@Column(name = "PARTY_ID", insertable = false, updatable = false)
private String partyId;
@Enumerated(value = EnumType.STRING)
@NotNull
private PartyState state;
}
持有主键的PartyId类看起来像这样,这就是映射似乎失败的地方:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PartyId implements Serializable {
private String tournament;
private String partyId;
}
在TournamentService类中,save会抛出异常:
@Transactional
public PartyEntityDTO createParty(String tournamentId) {
TournamentEntity tournament = tournamentRepository.getOne(tournamentId);
PartyEntity party = tournamentPartyRepository.save(PartyEntity.builder().tournament(tournament).state(REGISTERED).partyId(UUID.randomUUID().toString()).build());
return modelMapper.map(party, PartyEntityDTO.class);
}
然而,使用存储库直接工作完全正常。运行以下测试会将Party添加到数据库中。不涉及周围的交易注释
@RunWith(SpringRunner.class)
@SpringBootTest
//@Transactional
public class PartyDatabaseTest {
@Autowired
private TournamentPartyRepository partyRepository;
@Autowired
private TournamentRepository tournamentRepository;
@Test
public void testInsertEntry() {
TournamentEntity loadedTournament = tournamentRepository.findAll().get(0);
PartyEntity party = partyRepository
.save(PartyEntity
.builder()
.tournament(loadedTournament)
.partyId(UUID.randomUUID().toString())
.state(REGISTERED)
.build());
}
}
对于我做错的任何建议都将不胜感激!