我正在编写一个API,该API将一个在线数据库连接到一个android应用程序,并一直被困在如何创建一个DTO的过程中,该DTO从相互连接的3个表中获取数据。
这是我正在编写的第一个API,我仍然在努力学习良好的实践,所以欢迎任何建议。
我已经到了一个地步,我真的不知道在哪里寻找答案,因为我找到的所有答案都是解释如何使用查询从单个表中获取数据(可能是使用错误的术语搜索,因为我不是英语母语)。
这些是我在API中创建的实体:
员工
@Entity
@Table(name = "employees")
public class Employees {
@Id
@Column(name = "eid")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int eid;
@Column(name = "first_name")
private String first_name;
@Column(name = "last_name")
private String last_name;
@Column(name = "birth_date")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private Date birth_date;
@Column(name = "jid")
private int jid;
//Getters setters constructors
}工作
@Entity
@Table(name = "jobs")
public class Jobs {
@Id
@Column(name = "jid")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int jid;
@Column(name = "job_name")
private String job_name;
//Getters setters constructors
}凭据
@Entity
@Table(name = "credentials")
@IdClass(CredentialsCID.class)
public class Credentials {
@Id
@Column(name = "username")
private String username;
@Id
@Column(name = "is_admin")
private byte is_admin;
@Column(name = "password")
private String password;
@Column(name = "eid")
private int eid;
//Getters setters constructors
}这是dto类
EmployeesCustomDTO
package com.example.accessingdatamysql.dto;
import com.example.accessingdatamysql.model.Contracts;
import com.example.accessingdatamysql.model.Credentials;
import com.example.accessingdatamysql.model.Employees;
public class EmployeesCustomDTO {
private int eid;
private String first_name;
private String last_name;
private String jid;
private int hours;
private String type;
private byte is_admin;
public EmployeesCustomDTO() {
}
public EmployeesCustomDTO(int eid, String first_name, String last_name, String jid, int hours, String type, byte is_admin) {
this.eid = eid;
this.first_name = first_name;
this.last_name = last_name;
this.jid = jid;
this.hours = hours;
this.type = type;
this.is_admin = is_admin;
}
public int getEid() {
return eid;
}
public void setEid(int eid) {
this.eid = eid;
}
public String getFirst_name() {
return first_name;
}
public void setFirst_name(String first_name) {
this.first_name = first_name;
}
public String getLast_name() {
return last_name;
}
public void setLast_name(String last_name) {
this.last_name = last_name;
}
public String getJob_name() {
return jid;
}
public void setJob_name(String job_name) {
this.jid = job_name;
}
public int getHours() {
return hours;
}
public void setHours(int hours) {
this.hours = hours;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public byte getIs_admin() {
return is_admin;
}
public void setIs_admin(byte is_admin) {
this.is_admin = is_admin;
}
public EmployeesCustomDTO convertToDTO(Employees employees, Credentials credentials, Contracts contracts){
EmployeesCustomDTO employeesCustomDTO = new EmployeesCustomDTO();
employeesCustomDTO.setEid(employees.getEid());
employeesCustomDTO.setFirst_name(employees.getFirst_name());
employeesCustomDTO.setLast_name(employees.getLast_name());
employeesCustomDTO.setJob_name(String.valueOf(employees.getJid())); // TODO: 19/12/2020 check if correct
employeesCustomDTO.setType(contracts.getType());
employeesCustomDTO.setHours(contracts.getHours());
employeesCustomDTO.setIs_admin(credentials.getIs_admin());
return employeesCustomDTO;
}
}然后,我向EmployeesRepo添加了以下查询(在MySQL工作台上试用它时,它的工作方式与我所希望的一样)
@Repository
public interface EmployeesRepo extends JpaRepository<Employees, Integer> {
@Query(value = "SELECT employees.eid,employees.first_name,employees.last_name,employees.jid,contracts.hours,contracts.type,credentials.is_admin " +
"FROM employees,credentials,contracts " +
"WHERE employees.eid = credentials.eid AND contracts.eid = employees.eid", nativeQuery = true)
List<EmployeesCustomDTO> getCustomErgazomenoi();
}及其服务中的下列方法
@Override
public List<EmployeesCustomDTO> getCustomErgazomenoi() {
return employeesRepo.getCustomErgazomenoi();
}然后我调用控制器
@GetMapping("/custom-employees")
public List<EmployeesCustomDTO> getAllCustomEmployees(){return employeesService.getCustomErgazomenoi();}当我将请求发送到端点时,我会得到以下错误:
邮递员:
{
"timestamp": "2020-12-22T16:40:28.542+00:00",
"status": 500,
"error": "Internal Server Error",
"message": "",
"path": "/employees/custom-employees"
}来自intellij的终端
2020-12-22 18:40:28.527 ERROR 2948 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.core.co
nvert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type [com.example.accessingdatamysql.dto.EmployeesCustomDTO]] with root cause
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type [com.example.accessingdatamysql.dto.EmployeesCusto
mDTO]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:322) ~[spring-core-5.3.1.jar:5.3.1]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195) ~[spring-core-5.3.1.jar:5.3.1]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:175) ~[spring-core-5.3.1.jar:5.3.1]
at org.springframework.data.repository.query.ResultProcessor$ProjectingConverter.convert(ResultProcessor.java:309) ~[spring-data-commons-2.4.1.jar:2.4.1]
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.lambda$and$0(ResultProcessor.java:225) ~[spring-data-commons-2.4.1.jar:2.4.1]
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:236) ~[spring-data-commons-2.4.1.jar:2.4.1]
at org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:156) ~[spring-data-commons-2.4.1.jar:2.4.1]
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:158) ~[spring-data-jpa-2.4.1.jar:2.4.1]
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:143) ~[spring-data-jpa-2.4.1.jar:2.4.1]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137) ~[spring-data-commons-2.4.1.jar:2.4.1]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121) ~[spring-data-commons-2.4.1.jar:2.4.1]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:152) ~[spring-data-commons-2.4.1.jar:2.4.1]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:131) ~[spring-data-commons-2.4.1.jar:2.4.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.1.jar:5.3.1]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80) ~[spring-data-commons-2.4.1.jar:2.4.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.1.jar:5.3.1]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:371) ~[spring-tx-5.3.1.jar:5.3.1]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:134) ~[spring-tx-5.3.1.jar:5.3.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.1.jar:5.3.1]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) ~[spring-tx-5.3.1.jar:5.3.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.1.jar:5.3.1]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:145) ~[spring-data-jpa-2.4.1.jar:2.4.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.1.jar:5.3.1]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.1.jar:5.3.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.1.jar:5.3.1]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.1.jar:5.3.1]
at com.sun.proxy.$Proxy120.getCustomErgazomenoi(Unknown Source) ~[na:na]
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:564) ~[na:na]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.1.jar:5.3.1]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) ~[spring-aop-5.3.1.jar:5.3.1]
at com.sun.proxy.$Proxy77.getCustomErgazomenoi(Unknown Source) ~[na:na]
at com.example.accessingdatamysql.services.impl.EmployeesServiceImpl.getCustomErgazomenoi(EmployeesServiceImpl.java:45) ~[classes/:na]
at com.example.accessingdatamysql.controllers.EmployeesController.getAllCustomEmployees(EmployeesController.java:28) ~[classes/:na]
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:564) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197) ~[spring-web-5.3.1.jar:5.3.1]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141) ~[spring-web-5.3.1.jar:5.3.1]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.3.1.jar:5.3.1]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:893) ~[spring-webmvc-5.3.1.jar:5.3.1]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:807) ~[spring-webmvc-5.3.1.jar:5.3.1]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.1.jar:5.3.1]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1061) ~[spring-webmvc-5.3.1.jar:5.3.1]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:961) ~[spring-webmvc-5.3.1.jar:5.3.1]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.1.jar:5.3.1]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.1.jar:5.3.1]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:626) ~[tomcat-embed-core-9.0.39.jar:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.1.jar:5.3.1]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.39.jar:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.39.jar:9.0.39]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.1.jar:5.3.1]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.1.jar:5.3.1]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.1.jar:5.3.1]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.1.jar:5.3.1]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.1.jar:5.3.1]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.1.jar:5.3.1]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630) ~[na:na]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at java.base/java.lang.Thread.run(Thread.java:832) ~[na:na]虽然我找到了一些关于如何解决这个问题的答案,但我似乎无法让它在我的API上工作。有什么建议吗?
发布于 2020-12-22 15:41:11
您能提供EmployeesCustomDTO类的代码吗?看起来,您正在尝试执行DTO投影,这将要求您将SQL结果映射到DTO中的属性。
如果使用hibernate,可以在DTO和update查询上创建适当的构造函数以使用新的构造函数:
@Query(value = "SELECT com.example.accessingdatamysql.dto.EmployeesCustomDTO(employees.eid,employees.first_name,employees.last_name,employees.jid,contracts.hours,contracts.type,credentials.is_admin) " +
"FROM employees,credentials,contracts " +
"WHERE employees.eid = credentials.eid AND contracts.eid = employees.eid")
List<EmployeesCustomDTO> getCustomErgazomenoi(); 有关详细说明,请参见- https://vladmihalcea.com/the-best-way-to-map-a-projection-query-to-a-dto-with-jpa-and-hibernate/
无论哪种方式,您都必须提供从SQL结果集到DTO属性的映射。如果您遵循的是SQL和Java中的标准命名约定,则名称可能不相同--例如,您的查询引用是first_name,但我假设您的DTO将是firstName。
看起来,如果使用本机查询:https://thorben-janssen.com/dto-projections/#DTO_projections_for_native_SQL_queries,也可以通过https://thorben-janssen.com/dto-projections/#DTO_projections_for_native_SQL_queries提供映射。
类似的堆栈溢出帖子:
https://stackoverflow.com/questions/65411193
复制相似问题