Need help turning standard SQL query to JPA Criteria Query - java

I have two tables:
Employee
id
firstName
lastName
.
.
.
Training
id
employeeId
trainingName
trainingSuspsnseDate
trainingComplete
When I perform a standard SQL query in MySQL Workbench, it looks like this:
SELECT e.id, e.firstName, e.lastName, t.trainingName, t.trainingSuspenseDate, t.trainingComplete
FROM Employee e
JOIN Training t on t.employeeId = e.id
WHERE t.trainingSuspenseDate < CURDATE()
order by t.trainingSuspenseDate;
Now, I want to create a criteria query of the same SQL query, but I am having trouble with the join. This is what I have tried based on my googling:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> employeeQuery = builder.createQuery(Employee.class);
Root<Employee> employee = employeeQuery.from(Employee.class);
Join<Employee, Training> training = employee.join(Employee_.ID);
employeeQuery.select(builder.construct(Employee.class,
employee.get(Employee_.ID),
employee.get(Employee_.firstName),
employee.get(Employee_.lastName),
training.get(Training_trainingName),
training.get(Training_trainingSuspsnseDate),
training.get(Training_trainingComplete)));
However, I am getting the error:
incompatible types: inference variable Y has incompatible equality constraints Templates,Integer where Y,X are type-variables:
Y extends Object declared in method <Y>join(SingularAttribute<? super X,Y>)
X extends Object declared in interface From
I have tried other permutations of the JOIN, but I get different errors. I cannot seem to find the exact "secret" to creating this query.
Join<Employee, Training> training = training.join(Training_.employeeId);
or
Join<Employee, Training> training = training.join(Training_.employeeId).join(Employee_.ID);
or
Join<Training, Employee> training = training.join(Training_.employeeId);
or
Join<Training, Employee> training = training.join(Training_.employeeId).join(Employee_.ID);
or
.
.
.
EDIT: Added my model classes
Employee.java
#Entity
#Table(name = "employee")
#XmlRootElement
#NamedQueries(
{
#NamedQuery(name = "Employee.findAll", query = "SELECT e FROM Employee e"),
#NamedQuery(name = "Employee.deleteAll", query = "DELETE FROM Employee e"),
#NamedQuery(name = "Employee.countAll", query = "SELECT COUNT(e.ID) FROM Employee e")
})
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#GeneratedValue
#Column(name = "id")
private Integer ID;
#Basic(optional = true)
#Column(name = "name_first")
private String firstName;
#Basic(optional = true)
#Column(name = "name_last")
private String lastName;
#Basic(optional = true)
#Column(name = "created_date")
private String employeeDate;
#Basic(optional = true)
#Column(name = "personal_type")
private String personnelType;
public Employee() {
ID = 0;
}
public Employee(Integer id) {
this.ID = id;
}
public Integer getID() {
return ID;
}
public void setID(Integer id) {
this.ID = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmployeeDate() {
return employeeDate;
}
public void setEmployeeDate(String employeeDate) {
this.employeeDate = employeeDate;
}
public String getPersonnelType() {
return personnelType;
}
public void setPersonnelType(String personnelType) {
this.personnelType = personnelType;
}
}
Training.java
#Entity
#Table(name = "training")
#XmlRootElement
#NamedQueries(
{
#NamedQuery(name = "Training.findAll", query = "SELECT t FROM Training t"),
#NamedQuery(name = "Training.deleteAll", query = "DELETE FROM Training t"),
#NamedQuery(name = "Training.countAll", query = "SELECT COUNT(t.ID) FROM Training t")
})
public class Training implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#GeneratedValue
#Column(name = "ID")
private Integer ID;
#Basic(optional = false)
#Column(name = "employee_id")
private String employeeId;
#Basic(optional = false)
#Column(name = "training_name")
private String trainingName;
#Basic(optional = false)
#Column(name = "training_suspense_date")
private Date trainingSuspenseDate;
#Basic(optional = false)
#Column(name = "training_complete")
private Boolean trainingComplete;
public Integer getID() {
return ID;
}
public void setID(Integer ID) {
this.ID = ID;
}
public String getEmployeeId() {
return employeeId;
}
public void setEmployeeId(String employeeId) {
this.employeeId = employeeId;
}
public void setTrainingName(String trainingName) {
this.trainingName = trainingName;
}
public String getTrainingName() {
return trainingName;
}
public void setTrainingSuspenseDate(Date trainingSuspsenseDate) {
this.trainingSuspsenseDate = trainingSuspsenseDate;
}
public Date getTrainingSuspenseDate() {
return trainingSuspsenseDate;
}
public void setTrainingComplete(Boolean trainingComplete) {
this.trainingComplete = trainingComplete;
}
public Boolean getTrainingComplete() {
return trainingComplete;
}
}

I can figure out that You have a meta-model generated for your query.
So the best way will be to extends your entity definition as follow:
You have to add mapping in your Training class:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "employeeId")
private Employee employee;
Then in your Employee class add oposite reference:
#OneToMany(mappedBy = "employee")
private Set<Training> trainings = new HashSet<>();
Then change your criteria query to:
Join<Employee, Training> training = employee.join(Employee_.trainings);

You can try cross join. Native sql is a bit differerent but the result is as axpected
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> employeeQuery = builder.createQuery(Employee.class);
Root<Employee> employee = employeeQuery.from(Employee.class);
Root<Employee> training= employeeQuery.from(Training.class);
employeeQuery.select(builder.construct(Employee.class,
employee.get(Employee_.ID),
employee.get(Employee_.firstName),
employee.get(Employee_.lastName),
training.get(Training_.trainingName),
training.get(Training_.trainingSuspsnseDate),
training.get(Training_.trainingComplete)))
.where(builder.equal(employee.get(Employee_.ID), training.get(Training_.employeeId)));

Looking at your model classes, the entities are not related directly (even though the employeeId in Training is supposed to be a foreign key, it is not defined as such in the entity relationship. So, if you wish to work with the existing entities, without changing them, you would need the following -
A POJO (for example EmpRes) which maps the attributes as per the select clause. criteriaQuery should be initialized on this POJO as -
CriteriaQuery<EmpRes> criteriaQuery = builder
.createQuery(EmpRes.class);
As the entities are unrelated, the generated query will have a cross join.
The code would look like -
criteriaQuery.select(builder.construct(EmpRes.class, employee
.get(Employee_.getAttribute("ID").getName()), employee
.get(Employee_.getAttribute("firstName").getName()), employee
.get(Employee_.getAttribute("lastName").getName()), training
.get(Training_.getAttribute("trainingName").getName()),
training.get(Training_.getAttribute("trainingSuspenseDate")
.getName()), training.get(Training_.getAttribute(
"trainingComplete").getName())));
criteriaQuery.where(builder.equal(employee.get("ID"), training.get("employeeId")));
List<EmpRes> employees = entityManager.createQuery(criteriaQuery).getResultList();
However, if the entities can be changed (as should be the ideal design), an Employee has Training(s). So, a #OneToMany relationship between Employee and Training model classes should be defined as follows -
Employee.java
#OneToMany(mappedBy="employee")
private Set<Training> trainings = new HashSet<>();
Training.java
#ManyToOne
#JoinColumn(name = "employeeId")
private Employee employee;
CriteriaQuery related code -
Join<Employee, Training> trainingJoin = employee.join(Employee_.getAttribute("trainings").getName());
criteriaQuery.select(builder.construct(EmpRes.class, employee
.get(Employee_.getAttribute("ID").getName()), employee
.get(Employee_.getAttribute("firstName").getName()), employee
.get(Employee_.getAttribute("lastName").getName()),
trainingJoin.get(Training_.getAttribute("trainingName")
.getName()), trainingJoin.get(Training_.getAttribute(
"trainingSuspenseDate").getName()), trainingJoin
.get(Training_.getAttribute("trainingComplete")
.getName())));
You can then add the additional where clause based on your requirements.
A good reference to Criteria API is here.

This error message - incompatible types: inference variable Y has incompatible equality constraints - is an indication you need to carefully review DATA TYPES of the columns you are joining. The should be same data types on both sides of the = for performance and high speed comparisons.

Related

JPQL TypedQuery - setParamer does not work

I am trying to fetch an entity which has a one-to-one relation using a named Query. My "where" condition is on the relation entity. I am giving a named parameter. When I execute the query it ignores the parameter passed and giving me all the records.
I tried with positional parameter, it too didn't work.
Query
#NamedQuery(
name = "country.by.region",
query = " select c from Country c join Region r on r.id = :regid"
)
Country Entity
public class Country {
#Id
#Column(name = "COUNTRY_ID")
private String id;
#Column(name = "COUNTRY_NAME")
private String name;
#OneToOne(targetEntity = Region.class, cascade = CascadeType.ALL)
#JoinColumn(name = "REGION_ID")
private Region region;
// ...
}
Region Entity
public class Region {
#Id
#Column(name = "REGION_ID")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "regSeq")
private int id;
#Column(name = "REGION_NAME")
private String name;
// ...
}
DAO Impl
#Override
public List<Country> findBy(Region region) {
TypedQuery<Country> query = getEntityManager().createNamedQuery("country.by.region", Country.class);
query.setParameter("regid", region.getId());
query.setMaxResults(30);
return query.getResultList();
}
Try to correct your query in this way:
select c from Country c join c.region r where r.id = :regid
See also this section of the documentation.

Criteria API Unable to locate appropriate constructor on class

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?
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()));
}
The exception seems to me that Criteria likes to have an Investigator constructor that takes an Employee argument:
public Investigator(Employee nEmpId) {
super();
this.nEmpId = nEmpId;
}

How to find the reference when key to the find(Object.Class, {CompositeKey}) method is a composite key?

How to find a reference when we have composite key(two or more columns) to pass on as second parameter to the JPA entityManager.find(Object.class, compositeKey)?
My try-
I have created an Arraylist and added the values forming compositeKey it and then passing this list to the find method.
For ex: In my situation, userid and projectid together is the key for the UserProject table and these two have been added to the arraylist named as list, which will be passed as a second parameter to the entityManager find method as shown below:
List<Integer> list = new ArrayList<Integer>();
list.add(userProjectDO.getUserid());
list.add(userProjectDO.getProjectid());
UserProject userProject = em.find(UserProject.class,list);
But this always return as null, even though userid and projectId exists on the table. Has anyone been into similar issue? Solution?
JPA's EntityManager#find doesn't accept arrays as key but Object. Since you are talking about composite key you should implement your key in a separate class which will represent the composite key by listing all the key separate properties. You can achieve this using EmbeddedId for instance.
For example:
You should define the composite key class and annotate with #Embeddable:
public class UserProjectKey implements Serializable{
private String userId;
private String projectId;
//constructors, getters, setters
}
and use it as #EmbeddedId in your entity.
To search by the key you can do:
UserProjectKey key = new UserProjectKey("userIdExample", "projectIdExample");
em.find(UserProject.class, key);
I have found another approach i.e. writing namedQuery to search the table. Posting the implementation just in case it helps anyone.
final Query query = em.createNamedQuery("UserProject.findByAll");
UserProject Entity class:
#Entity
#Table(name = "userproject", schema = "public")
#NamedQueries({ #NamedQuery(name = "UserProject.findByAll", query = "SELECT a FROM UserProject a where a.userid = :userid and a.projectid = :projectid"),
#NamedQuery(name = "UserProject.findByUserId", query = "SELECT a FROM UserProject a where a.userid = :userid"),
#NamedQuery(name = "UserProject.findById", query = "SELECT a FROM UserProject a where a.id = :id" )})
public class UserProject implements Serializable {
private static final long serialVersionUID = 1L;
#Id #GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "userid")
private Integer userid;
#Column(name = "projectid")
private Integer projectid;
#Column(name = "created")
private Timestamp created;
#Column(name = "modified")
private Timestamp modified;
#Column(name = "modifiedbyid")
private Integer modifiedbyid;
#Column(name = "role")
private String role;
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public Integer getUserid() {
return userid;
}
public void setUserid(final Integer userid) {
this.userid = userid;
}
public void setProjectid(final Integer projectid) {
this.projectid = projectid;
}
public Timestamp getCreated() {
return created;
}
public void setCreated(final Timestamp created) {
this.created = created;
}
public Timestamp getModified() {
return modified;
}
public void setModified(final Timestamp modified) {
this.modified = modified;
}
public Integer getModifiedbyid() {
return modifiedbyid;
}
public void setModifiedbyid(final Integer modifiedbyid) {
this.modifiedbyid = modifiedbyid;
}
public String getRole() {
return role;
}
public void setRole(final String role) {
this.role = role;
}
}
And finally set the query parameters i.e. compositeKey values(userid,projectid) as :
final Query query = em.createNamedQuery("UserProject.findByAll");
query.setParameter("userid",userProjectDO.getUserid());
query.setParameter("projectid",userProjectDO.getProjectid());
List<UserProject> userProjectList = query.getResultList();
userProjectList would contain the row which matches the compositeKey (userId,projectId)
One advantage I see with this approach is that I can write N number of named queries inside the entity class as per the need/requirement. For ex: If we need to work on a view created out of this table. It can be easily achieved by first creating the view and then write another named query to work on it.

Join together 3 entities in Hibernate

I have the following entities:
Person.java
#Table(name = persons)
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "UserID", nullable = false)
private Long userId;
#Column(name = "Employeenumber", nullable = false) private String employeeNumber;
#Column(name = "Firstname", nullable = false) private String firstName;
#Column(name = "Lastname", nullable = false) private String lastName;
public User() { }
public User(String employeeNumber, String firstName, String lastName) {
super();
this.employeeNumber = employeeNumber;
this.firstName = firstName;
this.lastName = lastName;
}
/*
getter and setters
...
*/
}
Personhistory.java
#Entity
#Table(name = personhistory)
public class Personhistory {
#Id
#Column(name = "UserID", nullable = false)
private Long userId;
#Column(name = "Fromdate", nullable = false) private Date fromDate;
#Column(name = "Todate", nullable = false) private Date toDate;
#Column(name = "TeamID", nullable = false) private Integer teamId;
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "UnikId", nullable = false)
private Integer unikId;
public Userhistory() {
}
public Userhistory(Long userId, Date fromDate, Date toDate, int teamId) {
super();
this.userId = userId;
this.fromDate = fromDate;
this.toDate = toDate;
this.teamId = teamId;
}
/*
Getters and setters
...
*/
}
Team.java
#Entity
#Table(name = "team")
public class Team {
#Id
#Column(name = "TeamID")
#GeneratedValue(strategy = GenerationType.AUTO)
private int teamId;
#Column(name = "TeamNumber") private String teamNumber;
public Team() {}
public Team(String teamNumber) {
super();
this.teamNumber = teamNumber;
}
/*
Getters and setters
...
*/
}
I want to make a API call like this:
localhost:8080/users/{employee}
And get back an object containing the person (His emp-number, firstname and lastname), when he was at the team and what team that is.
If I were to write this query in MSSQL, it would look like this:
select * from persons p
join personhistory ph on ph.UserID = p.UserID
and ph.Fromdate <= cast(getdate() as date)
and ph.Todate >= cast(getdate() as date)
join team t on t.TeamID = ph.TeamID
where u.Employeenumber = '999'
I have searched around for different solutions like HQL, JPQL, Criteria and so on, but I'm unable to make it work.
Any help would be much appreciated.
AFAIK Hibernate 5.1 provides more generic joins but with prior versions you'd either have to use a cross join and add the conditions in the where-clause or provide a real relation between the entities and join on that relation (using the "with" keyword for additional join conditions).
Example (note that I left out many annotations for simplicity):
class Person {
#OneToMany( mappedBy = "user" )
Collection<Personhistory> history;
...
}
class Personhistory {
#ManyToOne
Person user;
#ManyToOne
Team team;
...
}
Then the query could become
select p, ph, t from Person p
join p.history ph with ph.fromdate <= :date and ph.toDate >= :date
join ph.team t
where p.employeeNumber = :number

How to search mySql database table by foreign key using JPA?

I have 2 classes (BusinessAccount and Projects (shown below) that are mapped to a MySql database) where a 1:M relationship exists between BusinessAccounts and Projects. I am successfully inserting data to the database but am having a problem when it comes to querying the database. The problem that I am having is that I have no getter or setter for the foreign key, 'contractor_id' in the Projects class. The query that I want to carry out is to return the list of the names of all projects for a given BusinessAccount, by searching by the foreign key reference in the Projects table. I can do this no problem in mySQL but as there is no reference to the contractor_id as a java entity in the Projects class, I'm not sure how to do this search from within my java class. (Note: I tried to declare the foreign key along with getters and setters in the Projects class but as I have these mapped by the 1:Many relationship in the class already, it wouldn't compile as they were flagged as duplicate entities.) I'm sure it's something obvious that I'm missing but any help is much appreciated!
public List<Projects> getProjectList() {
factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
EntityManager em = factory.createEntityManager();
List<Projects> projectList = new ArrayList<Projects>();
em.getTransaction().begin();
String sessionEmail=Util.getEmail();
Query myQuery = em.createQuery("SELECT u FROM BusinessAccount u WHERE u.email=:email");
myQuery.setParameter("email", sessionEmail);
List<BusinessAccount> userList=myQuery.getResultList();
BusinessAccount account =userList.get(0);
Query myQuery2 = em.createQuery("SELECT distinct p.* FROM BusinessAccount u "
+ "INNER JOIN Projects p ON p.contractor_id=:userID");
/*Note p.contractor_id above refers to the entity in the
mysql database (and won't work obviously), I want to refer
to it's java equivalent but am not sure how to do that*/
myQuery2.setParameter("userID", account.getId());
projectList=myQuery2.getResultList();
em.getTransaction().commit();
em.close();
return projectList;
}
#Entity
#Table(name = "business_accounts")
public class BusinessAccount {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "first_name")
private String firstName;
#Column(name = "surname")
private String surname;
#OneToMany(mappedBy = "businessAccount", fetch = FetchType.EAGER, cascade = { CascadeType.ALL })
private List<Projects> projects;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getSurname() {
return surname;
}
public List<Projects> getProjects()
{
if (projects == null)
{
projects = new ArrayList<Projects>();
}
return projects;
}
public void setProjects(List<Projects> projects)
{
this.projects = projects;
}
}
#Entity
#Table(name = "projects")
public class Projects {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int project_id;
#Column(name = "project_name")
private String projectName;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({ #JoinColumn(name = "contractor_id", referencedColumnName="id") })
private BusinessAccount businessAccount;
public BusinessAccount getBusinessAccount() {
if (businessAccount == null) {
businessAccount = new BusinessAccount();
}
return businessAccount;
}
public void setBusinessAccount(BusinessAccount businessAccount) {
this.businessAccount = businessAccount;
}
public int getProject_id() {
return project_id;
}
public void setProject_id(int project_id) {
this.project_id = project_id;
}
public String getProjectName() {
return projectName;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
}
The JPA query would be something like (you need to use the relation property, but no need for the foreign key itself - please try, it may need some tweaking):
SELECT p FROM BusinessAccount u, IN(u.projects) p WHERE u.id=:userId
But do you really need the query? You can get the related projects from the property:
BusinessAccount account = ...
List<Projects> projectList = account.getProjects();
Try this:
Query myQuery2 = em.createQuery("SELECT distinct p.* FROM BusinessAccount u "
+ "INNER JOIN Projects p ON p.businessAccount=:businessAccount");
myQuery2.setParameter("businessAccount", account);

Categories