Skip to content

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:

JPQL validation 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:

User.java
@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:

UserRepository.java - Wrong
@Repository
public 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:

UserRepository.java - Correct
@Repository
public 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:

Test verification
@Test
void 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:

JPQL vs SQL comparison
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-sensitive

When 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:

Wrong JPQL examples
// These are all WRONG:
u.first_name // Database column name
u.FirstName // Wrong case
u.FIRSTNAME // Wrong case
u.first_Name // Wrong case
// This is CORRECT:
u.firstName // Exact Java field name match

Common mistakes

I made a mental map to avoid these errors:

MistakeWrongCorrect
Using database columnu.first_nameu.firstName
Wrong entity nameFROM usersFROM User
Wrong caseu.Firstnameu.firstName
Mixing conventionsu.first_Nameu.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