SpringBoot/JPA按project_id排序触发PropertyReferenceException问题求助
问题场景
在SpringBoot/JPA(Postgres)项目中,定义了projects表:
create table projects( project_id int primary key, name varchar(255), description text );
控制器中原本按name排序的列表接口正常运行:
@GetMapping("/list") @ResponseBody public Page<Project> list(@AuthenticationPrincipal UserDetails currentUserDetails) { int page = 0; int size = 100; Sort sort = Sort.by("name").ascending(); PageRequest p = PageRequest.of(page, size, sort); return projectService.list(p); }
但将排序字段改为project_id后:
Sort sort = Sort.by("project_id").ascending();
运行时抛出异常:
2024-01-01T14:34:04,424 ERROR [http-nio-8081-exec-6] o.a.j.l.DirectJDKLog: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.data.mapping.PropertyReferenceException: No property 'project' found for type 'Project'] with root cause
org.springframework.data.mapping.PropertyReferenceException: No property 'project' found for type 'Project'
at org.springframework.data.mapping.PropertyPath.(PropertyPath.java:90)
对应的Project实体类定义:
@Entity @Table(name = "Projects") public class Project { @Id @GeneratedValue(generator = "ProjectSeq") @SequenceGenerator(name = "ProjectSeq", sequenceName = "PROJECTS_PROJECT_ID_SEQ", allocationSize = 1) Integer project_id; String name; public Integer getProject_id() { return project_id; } public void setProject_id(Integer project_id) { this.project_id = project_id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } String description; }
疑问:这是否是保留字相关问题?
问题原因与解决方案
这不是Postgres保留字问题,根源是Spring Data JPA的属性命名解析规则:
Spring Data JPA在解析排序参数时,会把下划线_当作驼峰命名的分隔符,将project_id拆分为project和id,尝试查找Project类中名为project的属性,显然不存在,因此抛出PropertyReferenceException。
解决方法1:遵循Java驼峰命名规范(推荐)
修改实体类的字段名和对应的getter/setter为Java驼峰格式,通过@Column注解映射到数据库的下划线字段:
@Entity @Table(name = "Projects") public class Project { @Id @GeneratedValue(generator = "ProjectSeq") @SequenceGenerator(name = "ProjectSeq", sequenceName = "PROJECTS_PROJECT_ID_SEQ", allocationSize = 1) @Column(name = "project_id") // 映射数据库字段 Integer projectId; // 驼峰命名字段 String name; String description; // 对应的驼峰格式getter/setter public Integer getProjectId() { return projectId; } public void setProjectId(Integer projectId) { this.projectId = projectId; } // 其他getter/setter保持不变... }
然后修改排序代码,使用驼峰格式的属性名:
Sort sort = Sort.by("projectId").ascending();
解决方法2:直接指定数据库列名(无需修改实体类)
如果不想修改实体类的命名,可以使用JpaSort.unsafe()方法绕过Spring Data JPA的属性解析,直接指定数据库的列名:
Sort sort = JpaSort.unsafe("project_id").ascending();
这种方式会直接将排序字段作为数据库列名传入SQL,避免属性解析错误。
内容的提问来源于stack exchange,提问作者Black

