Why Does JPQL Fail When Using Database Column Names Instead of Java Field Names
Problem
When I wrote a JPQL query using the database column name first_name, I got this error:
Caused by: java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List com.example.repository.UserRepository.findByFirstName(java.lang.String)
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to resolve path [u.first_name], unexpected token [first_name] [SELECT u FROM User u WHERE u.first_name = :name]I knew the column existed in the database, so why couldn’t JPQL find it?
Environment
- Spring Boot 3.2.x
- Spring Data JPA 3.2.x
- PostgreSQL database
- Hibernate as JPA provider
What happened?
I had an entity with a mapped column name:
@Entity@Table(name = "users")public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
@Column(name = "first_name") // Database column is "first_name" private String firstName; // Java field is "firstName"
@Column(name = "last_name") private String lastName;}I wrote a query using the database column name:
@Repositorypublic interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT u FROM User u WHERE u.first_name = :name") List<User> findByFirstName(@Param("name") String name);}This failed because JPQL doesn’t know about database column names.
How to solve it?
The fix was simple—use the Java field name instead:
@Repositorypublic interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT u FROM User u WHERE u.firstName = :name") List<User> findByFirstName(@Param("name") String name);}I verified the fix:
@Testvoid givenUser_whenFindByFirstName_thenReturnsUser() { User user = new User(); user.setFirstName("John"); userRepository.save(user);
List<User> result = userRepository.findByFirstName("John");
assertEquals(1, result.size()); assertEquals("John", result.get(0).getFirstName());}The reason
JPQL (Java Persistence Query Language) is fundamentally different from SQL:
SQL: Queries database tables and columns ↓ Uses: table names, column names Case: Often case-insensitive
JPQL: Queries Java entity objects ↓ Uses: entity class names, Java field names Case: Case-sensitiveWhen you write SELECT u FROM User u, JPQL looks for an entity class named User, not a table named users. When you write u.firstName, it looks for a Java field named firstName, not a database column.
The @Column(name = "first_name") annotation tells JPA how to map the Java field to the database column when generating SQL. But JPQL operates at the entity level, not the database level.
Case sensitivity matters
JPQL is case-sensitive for entity names and field names:
// These are all WRONG:u.first_name // Database column nameu.FirstName // Wrong caseu.FIRSTNAME // Wrong caseu.first_Name // Wrong case
// This is CORRECT:u.firstName // Exact Java field name matchCommon mistakes
I made a mental map to avoid these errors:
| Mistake | Wrong | Correct |
|---|---|---|
| Using database column | u.first_name | u.firstName |
| Wrong entity name | FROM users | FROM User |
| Wrong case | u.Firstname | u.firstName |
| Mixing conventions | u.first_Name | u.firstName |
Summary
In this post, I explained why JPQL fails when using database column names. The key point is that JPQL queries Java entities using Java field names with exact case matching, not database column names.
When your @Query validation fails with “Unable to resolve path”, check that you’re using the Java field name from your entity class, not the database column name from @Column.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments