【问题标题】:Spring Data JPA repository methods don't recognize property names with underscoresSpring Data JPA 存储库方法无法识别带有下划线的属性名称
【发布时间】:2015-07-11 01:25:48
【问题描述】:

我在实体属性名称中有下划线,当 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/

如果您的属性名称包含下划线(例如 first_name),您可以 使用第二个下划线转义方法名称中的下划线。为了 必须命名查询方法的 first_name 属性 findByFirst__name(…)。

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

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

【问题讨论】:

    标签: spring-data-jpa


    【解决方案1】:

    如果您无法更改我的情况下的实体,那么最好在存储库方法之上使用 jqpl 查询或本机 sql 查询

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

    【讨论】:

    • @Query("select s from Student s where s.s_name=:s_name") Set&lt;Student&gt; findBySName(String s_name); 为我工作
    【解决方案2】:

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

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

    由于我们将下划线视为保留字符,因此我们强烈建议您 遵循标准的 Java 命名约定(即不使用下划线) 属性名称,而不是驼峰式大小写)。

    this JIRA issue 说明了为什么使用此建议更新了文档,并删除了描述双下划线选项的部分。

    我怀疑你的根本问题是 Spring/Hibernate 没有将骆驼案例属性名称映射到数据库中列的蛇案例名称。您真正需要的是在休眠生成为 S_NAME 的 SQL 中解释您的属性名称。

    这就是为什么您的属性名称中的下划线是“必需”?如果是这样,有几个解决方案:

    选项 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>
    

    此命名策略会将 camelCase 转换为 SNAKE_CASE。那么你的类可以看起来像这样简单:

    @Entity
    public class Student {
         @Id
         private String sId;
         private String sName;
    
         //...getters and setters...
    }
    

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

     S_ID
     S_NAME
    

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

    终点线:

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

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

    【讨论】:

    • 嗨,我正在使用 @Column 注释,但它仍然无法正常工作并抛出异常 - 线程“main”org.springframework.dao.InvalidDataAccessApiUsageException 中的异常:无法找到具有给定名称的属性 [ District_id] 在这个 ManagedType [DBData] 上;嵌套异常是 java.lang.IllegalArgumentException: Unable to locate Attribute with the given name [district_id] on this ManagedType
    • 你好 aru007。没有看到你的代码和数据模型很难说。我建议发布有关此异常的新堆栈溢出问题。我的猜测是您的名字 District_id 不在数据库中的实体上,但是在错误上的快速谷歌搜索显示了许多可能出错的可能性。如果您发布一个新问题,我会看看它!
    【解决方案3】:

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

    【讨论】:

    • 这个问题最体贴的回答。
    猜你喜欢
    • 2014-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-23
    • 2018-08-25
    • 2017-08-20
    • 2015-07-13
    • 2020-08-24
    相关资源
    最近更新 更多