Reputation: 251
I'm using a JPA query that uses a specification to retrieve entities. When I execute the query, I'm getting the error:
org.springframework.data.mapping.PropertyReferenceException: No property name found for type Task!
I've looked at the answers to similar questions that have been asked on this site previously & tried to model my code to follow the patterns that were recommended but the code is still failing.
When I step through the code with a debugger, the expanded path in the criteria builder is returning the embedded ID class, but when the specification is actually used in the query it looks like the attribute is being applied to the base entity class.
Am I missing something obvious?
Here is the entity class:
@Entity
@Table(name = "TASKS")
public class Task implements Serializable {
@EmbeddedId
private TaskId id;
...more attributes, getters and setters
}
Here is the embedded ID entity class:
@Embeddable
public class TaskId implements Serializable {
@Column(name = "NAME", length = 100)
private String name;
...more attributes, getters and setters
}
Here is the specification builder that matches on the embedded id 'name' attribute:
public class HasTaskNameSpec {
private HasTaskNameSpec() {
}
public static Specification<Task> equals(String name) {
return (root, query, criteriaBuilder) -> {
return criteriaBuilder.equal(root.get("id").get("name"), taskName);
};
}
}
The query is executed on the repository as follows:
List<Task> results = taskRepository.findAll(HasTaskNameSpec.equals("foo"));
The repository itself is very simple:
public interface TaskRepository extends JpaRepository<Task, TaskId>, JpaSpecificationExecutor<Task> {
List<Task> findByIdName(String name);
Page<Task> findByIdName(String name, Pageable page);
}
** EDIT added methods to repository as was suggested below **
Upvotes: 6
Views: 12250
Reputation: 3548
root.get({embeddedIdName}).get({subPropertyName})
is used to query on embeddedId using specification.
@Embeddable
public class ProjectId implements Serializable{
private static final long serialVersionUID = 1L;
@Column(name = "PROJECT_NAME")
private String projectName;
@Column(name = "ORGANIZATION")
private String organization;
......
......
}
@Entity
@Table(name = "projects")
public class Project {
@EmbeddedId
private ProjectId projectId;
@Column(name = "STARTED_TIME")
private Timestamp startedTime;
@Column(name = "ACTIVE")
private String active;
@Column(name = "DESCRIPTION")
private String description;
......
......
}
In the above snippet, ProjectId is an embedded id. To query on projectName, we should use below snippet.
expression = root.get("projectId").get("projectName");
Upvotes: 5
Reputation: 251
Ahh, the root cause was totally in our codebase. There was a sort order being specified on the page that didn't include the embedded "id" attribute. The above code works.
Upvotes: 4
Reputation: 466
Take a look at this link which has a similar query.
The final answer suggests that you can add a method to your TaskRepository thus.
public interface TaskRepository extends JpaRepository<Task, TaskId>, JpaSpecificationExecutor<Task> {
public List<Task> findByIdName(String name);
}
Upvotes: 3