Criteria API Unable to locate appropriate constructor on class

Jacob :

When I am implementing the Criteria API join for my spring boot study, I tried joining 2 classes and fetching the result. But when I am implementing and running I am getting the following error,

Unable to locate appropriate constructor on class [com.spacestudy.model.Investigator]. Expected arguments are: com.spacestudy.model.Employee
[cause=org.hibernate.PropertyNotFoundException: no appropriate constructor in class: com.spacestudy.model.Investigator]

And my Employee.java class like the following,

@Entity
@Table(name="employee")
public class Employee implements Serializable
{
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY, generator = "employee_seq_generator")
@SequenceGenerator(name = "employee_seq_generator", sequenceName = "employee_seq",allocationSize=1)
@Column(name="nemp_id",columnDefinition="serial")
public Integer nEmpId;

@Column(name="semp_name")
public String sEmpName;

@Column(name="sdesignation")
public String sDesignation;

@Column(name="ninst_id")
public Integer nInstId;

@Column(name="ndept_id")
public Integer nDeptId;

@Column(name="sclient_emp_id")
public String sClientEmpId;

@Column(name="ntemp_emp_id")
public Integer nTempEmpId;

@Column(name="bis_paid")
public boolean bIsPaid=true;

@Column(name="sunpaid_comment")
public String sUnpaidComment;

@ManyToOne(optional=true)
@JoinColumn(name="ndept_id", insertable = false, updatable = false)
public Department department;

@OneToMany(cascade = CascadeType.ALL,mappedBy="nEmpId")
public Set<Investigator> employeeInvestigatorJoinMapping;

public Employee() {
}

public Employee(Integer nEmpId, String sEmpName, String sDesignation, Integer nInstId, Integer nDeptId,
        String sClientEmpId, Integer nTempEmpId, boolean bIsPaid, String sUnpaidComment, Department department,
        Set<Investigator> employeeInvestigatorJoinMapping) {
    super();
    this.nEmpId = nEmpId;
    this.sEmpName = sEmpName;
    this.sDesignation = sDesignation;
    this.nInstId = nInstId;
    this.nDeptId = nDeptId;
    this.sClientEmpId = sClientEmpId;
    this.nTempEmpId = nTempEmpId;
    this.bIsPaid = bIsPaid;
    this.sUnpaidComment = sUnpaidComment;
    this.department = department;
    this.employeeInvestigatorJoinMapping = employeeInvestigatorJoinMapping;
   }    
 }

And my second class Investigator.java,

@Entity
@Table(name = "investigator")
@JsonInclude(JsonInclude.Include.NON_NULL) // avoiding null values
public class Investigator implements Serializable 
{
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "investigator_seq_generator")
@SequenceGenerator(name = "investigator_seq_generator", sequenceName = "investigator_seq")

@Column(name="ninvestigator_id")
public Integer nInvestigatorId;

@Column(name="sinvestigator_name")
public String sInvestigatorName;

@Column(name="ninst_id")
public Integer nInstId;

@Column(name="stitle")
public String sTitle;

@Column(name="ntemp_investigator_id")
public Integer nTempInvestigatorId;

@ManyToOne(optional = false)
@JoinColumn(name="nemp_id",referencedColumnName="nemp_id")
public Employee nEmpId;

// Default Constructor.
public Investigator()
{
}
public Investigator(Integer nInvestigatorId, String sInvestigatorName, Integer nInstId, String sTitle,
        Integer nTempInvestigatorId, Employee nEmpId) {
    super();
    this.nInvestigatorId = nInvestigatorId;
    this.sInvestigatorName = sInvestigatorName;
    this.nInstId = nInstId;
    this.sTitle = sTitle;
    this.nTempInvestigatorId = nTempInvestigatorId;
    this.nEmpId = nEmpId;
   }
}

And Implemented the Criteria API joining like the following,

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Investigator> cq = cb.createQuery(Investigator.class);
Root<Employee> rootInvestigator = cq.from(Employee.class);
Join<Employee ,Investigator> resultEmployeeMappingObj 
    = rootInvestigator.join("employeeInvestigatorJoinMapping");
cq.multiselect(rootInvestigator);
cq.where(cb.equal(resultEmployeeMappingObj.get("nEmpId"), 21638));
List<Investigator> results = em.createQuery(cq).getResultList();
return results;

Where did I go wrong?

Evgeniy Khyst :

Criteria API

You have a few mistakes in the Criteria API query.

The working one looks like this

@Transactional(readOnly = true)
public List<Investigator> findByEmployeeId(int employeeId) {
  CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
  CriteriaQuery<Investigator> query = criteriaBuilder.createQuery(Investigator.class);
  Root<Investigator> investigator = query.from(Investigator.class);
  Join<Investigator, Employee> employees = investigator.join("nEmpId");
  query.select(investigator)
      .where(criteriaBuilder.equal(employees.get("nEmpId"), employeeId));
  TypedQuery<Investigator> typedQuery = em.createQuery(query);
  List<Investigator> investigators = typedQuery.getResultList();
  log.debug("Investigators: {}", investigators);
  return investigators;
}

Spring Data JPA

Also, if your application is based on Spring Framework after renaming a few fields you can use Spring Data JPA and do not write query at all.

Employee entity:

@Entity
@Table(name = "employee")
public class Employee implements Serializable {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "employee_seq_generator")
  @SequenceGenerator(name = "employee_seq_generator", sequenceName = "employee_seq", allocationSize = 1)
  @Column(name = "nemp_id", columnDefinition = "serial")
  public Integer id;

  //...

  @OneToMany(cascade = CascadeType.ALL, mappedBy = "employee")
  public Set<Investigator> investigators = new HashSet<>();

  //...
}

Investigator entity:

@Entity
@Table(name = "investigator")
@JsonInclude(JsonInclude.Include.NON_NULL) // avoiding null values
public class Investigator implements Serializable {

  //...

  @ManyToOne(optional = false)
  @JoinColumn(name = "nemp_id", referencedColumnName = "nemp_id")
  public Employee employee;

  //...
}

Spring Data JPA repository interface:

public interface InvestigatorRepository extends JpaRepository<Investigator, Integer> {

  List<Investigator> findByEmployeeId(int employeeId);
}

That's it. Now you can simply inject the repository and use it:

@Autowired
private InvestigatorRepository investigatorRepository;

public void testQuery() {
    investigatorRepository.findByEmployeeId(employee.getId()));
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=336745&siteId=1