Spring Data JPA 存储库方法无法识别 属性 带下划线的名称

Spring Data JPA repository methods don't recognize property names with underscores

我在实体 属性 名称中有下划线,当 Spring 尝试创建 JPA 存储库实现时,它导致异常试图解析 属性 的名称.

实体:

@Entity
public class Student {
      @Id
      private String s_id;
      private String s_name;
      ...
}

存储库:

 @Repository
 @Transactional
 public interface StudentRepository extends CrudRepository<Student, String> {

       List<Student> findByS__name(String name);

}

异常:

org.springframework.data.mapping.PropertyReferenceException: 
No property s found for type Student

这里说的是http://docs.spring.io/spring-data/jpa/docs/current/reference/html/

If your property names contain underscores (e.g. first_name) you can escape the underscore in the method name with a second underscore. For a first_name property the query method would have to be named findByFirst__name(…).

我只是按照文档说的做了,但我仍然得到异常。 我不想自己写 @Query,我的 属性 名字需要下划线,如何解决这个问题?

我使用 Spring data jpa 1.8.0.RELEASE + hibernate 4.3.9.Final

如果您可以控制 属性 命名,请避免在实体 属性 名称 中使用下划线。这将解决您的存储库问题,并将产生更清晰的代码库。在您之后处理代码的开发人员会感谢您。

请注意,这不仅仅是我的意见:Spring specifically discourages using underscores

As we treat underscore as a reserved character we strongly advise to follow standard Java naming conventions (i.e. not using underscores in property names but camel case instead).

this JIRA issue 显示了为什么使用此推荐更新文档,并且删除了描述双下划线选项的部分。

我怀疑您的根本问题 是 Spring/Hibernate 没有将驼峰式 属性 名称映射到您在数据库。您真正需要的是让您的 属性 名称在 hiberate 生成的 SQL 中解释为 S_NAME。

这就是为什么你的 属性 名字中的下划线是 "required" 吗?如果是这样,有几个解决方案:

选项 1:@Column 注释

要让 JPA/Hibernate 映射到正确的列名,您可以明确地告诉它名称。使用注释 @Column(name="...") 告诉它在 SQL 中使用什么列名。那么字段名就不受列名的约束了

@Entity
public class Student {
     @Id
     @Column(name="s_id")
     private String sId;
     @Column(name="s_name")
     private String sName;

     //...getters and setters...
}

选项 2:改进的命名策略
或者,如果您的应用程序有大量实体,而不是将 @Column 添加到每个 属性,请将配置文件中的默认命名策略更改为 hibernate improved naming strategy

<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>

此命名策略会将驼峰式转换为 SNAKE_CASE。那么你的 class 看起来就像这样简单:

@Entity
public class Student {
     @Id
     private String sId;
     private String sName;

     //...getters and setters...
}

使用这些选项中的任何一个,当它创建 SQL 时,它会将列名称解析为:

 S_ID
 S_NAME

注意:如果你正在使用,或者可以使用Spring启动,自动配置默认会使用SpringNamingStrategy,这是hibernate改进策略的一个稍微修改的版本。您无需执行任何操作即可获得此改进的命名策略。

终点线:

在您的 属性 名称中使用驼峰式大小写,您可以使用驼峰式大小写编写您的存储库方法名称,并且您可以停止尝试争论双下划线:

@Repository
@Transactional
public interface StudentRepository extends CrudRepository<Student, String> {  
       List<Student> findBySName(String name);   
}

写双下划线,即写 findByS__Name() for 属性 name s_name 是行不通的。我已经尝试并测试过它。按照上面的答案并更改实体中现有实例变量的名称 class。只是不要更改 getter 和 setter,因为它们可能会在现有代码中使用。

如果你不能改变我的情况下的实体,那么最好使用 jpql 查询或在存储库方法之上的本机 sql 查询

@Query("select s from Student s where s.s_name=?")
List<Student> findBySName();