JPA,Hibernate:在现有工作 DTO 中添加新变量时“无法在类上找到适当的构造函数”
Posted
技术标签:
【中文标题】JPA,Hibernate:在现有工作 DTO 中添加新变量时“无法在类上找到适当的构造函数”【英文标题】:JPA, Hibernate: "Unable to locate appropriate constructor on class" on adding new variables in an existing working DTO 【发布时间】:2020-12-26 22:24:08 【问题描述】:我的 DTO -
data class PodcastDTO(val id: Long, val author: String, val title:String, val description: String,
val categoryId: Long, val subCategoryId: Long,
val categoryName: String, val subCategoryName: String?): Serializable
我的查询 -
@Query("SELECT new com.krtkush.sample.modules.podcast.models.PodcastDTO" +
"(p.id, p.author, p.title, p.description, p.categoryId, p.subCategoryId, c.name, c2.name) " +
"FROM Podcast p " +
"LEFT JOIN Category c ON p.categoryId = c.id " +
"LEFT JOIN Category c2 ON p.subCategoryId = c2.id " +
"WHERE p.owner = :ownerId")
fun getPodcastsByOwner(@Param("ownerId")ownerId: Long): List<PodcastDTO>
当我尝试构建我的应用程序时,我收到以下错误 -
Unable to locate appropriate constructor on class [com.krtkush.audiotime.modules.podcast.models.PodcastDTO]. Expected arguments are: long, java.lang.String, java.lang.String, java.lang.String, java.lang.Long, long, java.lang.String, java.lang.String [SELECT new com.krtkush.audiotime.modules.podcast.models.PodcastDTO(p.id, p.author, p.title, p.description, p.categoryId, p.subCategoryId, c.name, c2.name) FROM com.krtkush.audiotime.modules.podcast.models.Podcast p LEFT JOIN com.krtkush.audiotime.modules.category.models.Category c ON p.categoryId = c.id LEFT JOIN com.krtkush.audiotime.modules.category.models.Category c2 ON p.subCategoryId = c2.id WHERE p.owner = :ownerId]
完整的错误是-
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'podcastRepository': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List com.krtkush.audiotime.modules.podcast.repositories.PodcastRepository.getPodcastsByOwner(long)!
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:178) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:101) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1821) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getObjectForBeanInstance(AbstractAutowireCapableBeanFactory.java:1266) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:260) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:621) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:609) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.data.repository.config.DeferredRepositoryInitializationListener.onApplicationEvent(DeferredRepositoryInitializationListener.java:51) ~[spring-data-commons-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.data.repository.config.DeferredRepositoryInitializationListener.onApplicationEvent(DeferredRepositoryInitializationListener.java:36) ~[spring-data-commons-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:404) ~[spring-context-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:361) ~[spring-context-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:898) ~[spring-context-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:554) ~[spring-context-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at com.krtkush.audiotime.AudioTimeApplicationKt.main(AudioTimeApplication.kt:13) ~[main/:na]
Caused by: java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List com.krtkush.audiotime.modules.podcast.repositories.PodcastRepository.getPodcastsByOwner(long)!
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:93) ~[spring-data-jpa-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.<init>(SimpleJpaQuery.java:63) ~[spring-data-jpa-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromMethodWithQueryString(JpaQueryFactory.java:76) ~[spring-data-jpa-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromQueryAnnotation(JpaQueryFactory.java:56) ~[spring-data-jpa-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$DeclaredQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:146) ~[spring-data-jpa-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:216) ~[spring-data-jpa-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:81) ~[spring-data-jpa-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lookupQuery(QueryExecutorMethodInterceptor.java:99) ~[spring-data-commons-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lambda$mapMethodsToQuery$1(QueryExecutorMethodInterceptor.java:92) ~[spring-data-commons-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) ~[na:na]
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133) ~[na:na]
at java.base/java.util.Collections$UnmodifiableCollection$1.forEachRemaining(Collections.java:1052) ~[na:na]
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[na:na]
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) ~[na:na]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.mapMethodsToQuery(QueryExecutorMethodInterceptor.java:94) ~[spring-data-commons-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lambda$new$0(QueryExecutorMethodInterceptor.java:84) ~[spring-data-commons-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at java.base/java.util.Optional.map(Optional.java:265) ~[na:na]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.<init>(QueryExecutorMethodInterceptor.java:84) ~[spring-data-commons-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:331) ~[spring-data-commons-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:297) ~[spring-data-commons-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.data.util.Lazy.getNullable(Lazy.java:212) ~[spring-data-commons-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.data.util.Lazy.get(Lazy.java:94) ~[spring-data-commons-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:244) ~[spring-data-commons-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:57) ~[spring-data-commons-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:171) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
... 24 common frames omitted
Caused by: java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate appropriate constructor on class [com.krtkush.audiotime.modules.podcast.models.PodcastDTO]. Expected arguments are: long, java.lang.String, java.lang.String, java.lang.String, java.lang.Long, long, java.lang.String, java.lang.String [SELECT new com.krtkush.audiotime.modules.podcast.models.PodcastDTO(p.id, p.author, p.title, p.description, p.categoryId, p.subCategoryId, c.name, c2.name) FROM com.krtkush.audiotime.modules.podcast.models.Podcast p LEFT JOIN com.krtkush.audiotime.modules.category.models.Category c ON p.categoryId = c.id LEFT JOIN com.krtkush.audiotime.modules.category.models.Category c2 ON p.subCategoryId = c2.id WHERE p.owner = :ownerId]
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:138) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:725) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:113) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:366) ~[spring-orm-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at com.sun.proxy.$Proxy114.createQuery(Unknown Source) ~[na:na]
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:87) ~[spring-data-jpa-2.3.1.RELEASE.jar:2.3.1.RELEASE]
... 52 common frames omitted
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate appropriate constructor on class [com.krtkush.audiotime.modules.podcast.models.PodcastDTO]. Expected arguments are: long, java.lang.String, java.lang.String, java.lang.String, java.lang.Long, long, java.lang.String, java.lang.String [SELECT new com.krtkush.audiotime.modules.podcast.models.PodcastDTO(p.id, p.author, p.title, p.description, p.categoryId, p.subCategoryId, c.name, c2.name) FROM com.krtkush.audiotime.modules.podcast.models.Podcast p LEFT JOIN com.krtkush.audiotime.modules.category.models.Category c ON p.categoryId = c.id LEFT JOIN com.krtkush.audiotime.modules.category.models.Category c2 ON p.subCategoryId = c2.id WHERE p.owner = :ownerId]
at org.hibernate.hql.internal.ast.QuerySyntaxException.convert(QuerySyntaxException.java:74) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.hql.internal.ast.ErrorTracker.throwQueryException(ErrorTracker.java:93) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:282) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:192) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:144) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:113) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:73) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:162) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:604) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:716) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
... 60 common frames omitted
Process finished with exit code 1
但是,如果我从查询中删除 p.categoryId, p.subCategoryId
并从 DTO 中删除相应字段,一切正常。
@Query("SELECT new com.krtkush.audiotime.modules.podcast.models.PodcastDTO" +
"(p.id, p.author, p.title, p.description, c.name, c2.name) " +
"FROM Podcast p " +
"LEFT JOIN Category c ON p.categoryId = c.id " +
"LEFT JOIN Category c2 ON p.subCategoryId = c2.id " +
"WHERE p.owner = :ownerId")
fun getPodcastsByOwner(@Param("ownerId")ownerId: Long): List<PodcastDTO>
和,
data class PodcastDTO(val id: Long, val author: String, val title:String, val description: String,
val categoryName: String, val subCategoryName: String?): Serializable
上面的代码完美无缺。我尝试了一种不同的方法,但最终也出现了问题,正如here
所解释的那样请帮忙。
【问题讨论】:
> 在查询中选择 p.subCategoryId 和 p.categoryId 以匹配构造函数。它是匹配的,对吧?还是我错过了什么? 为什么 Hibernate 期望long
对应 subCategoryId
?它期望其他人使用Long
。
我也注意到了。 id
也是如此。
这应该行得通!您可以尝试按预期声明一个辅助构造函数来验证,主构造函数是否使用不同的签名创建。
能否给我看一些二级构造函数的代码?
【参考方案1】:
正如@Micheal 所指出的,我也注意到了,休眠的 long 和 Long 之间存在不匹配。对于所有长变量,我必须在我的 DTO 中明确使用 java.lang.Long
。这可能是与 Kotlin 一起使用时 hibernate 中的一个错误。
【讨论】:
很遗憾我没有写这个作为答案:-) 我一直在我的 Kotlin 实体中使用Int
并且从未遇到任何问题(还)。以上是关于JPA,Hibernate:在现有工作 DTO 中添加新变量时“无法在类上找到适当的构造函数”的主要内容,如果未能解决你的问题,请参考以下文章
简述 JPA 与 Spring Data JPA 与 Hibernate