Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA - How to query using Specification and @EmbeddedId?

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 **

like image 314
Javaddict Avatar asked Dec 19 '17 14:12

Javaddict


3 Answers

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.

like image 118
Javaddict Avatar answered Nov 14 '22 22:11

Javaddict


'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");

Demo application link.

like image 32
Hari Krishna Avatar answered Nov 15 '22 00:11

Hari Krishna


Take a look at this link which has a similar query.

EmbbededId Lookup

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);
}
like image 40
AdamPillingTech Avatar answered Nov 15 '22 00:11

AdamPillingTech