Select self referencing table with spring data into new object - spring

I have a self referencing employee table. An Employee reports to his immediate lead which also an Employee.
fields->
id, name, employee_type, lead_id
I have mapped this table into this class,
public Class Employee {
private Integer id;
private String name;
private Integer employeeType; // 1-manager, 2-project lead, 3-developer, etc
private List<Employee> reporters;
}
How can I load all managers with his reporters using Spring Data JPA custom mapping? (those reporting employees will have their own reporters)
Mainly, I don't know how to map the corresponding list.
#Query("SELECT new Employee(id, name, employee_type) FROM employee")
List<Employee> findAllManagers();

Related

Spring Boot: How to create a new entity that references exisiting ones (by Id) [duplicate]

I have been playing around with JPA and came across this scenario and wanted to know how to solve this.
I have 2 tables namely Company and Employee.
So here an employee can work for only 1 company, therefore #OneToOne uni-directional mapping is done in Employee class. And the company details in the Company table would already exist.
So when I try to insert a record into Employee table, I even create a reference to the company, add it to the Employee class and save it using my EmployeeRepository's save method. Since the company_id would already exist in Company table, it should just refer it instead of creating a new company. But this is not happening.
I get an exception saying company object is still in the transient state. I can solve this by adding CascadeType.All but I don't need to insert the company rather I have to just link the company to the employee.
Here are the code snippets.
Employee Class
#Entity
#Table(name = "employee")
#Setter
#Getter
public class Employee
{
#Id
#GeneratedValue
private Long id;
#Column(name = "employee_id")
private Integer employeeId;
#Column(name = "employee_name")
private String employee_name;
#OneToOne
#JoinColumn(name = "company_id")
private Company company;
}
Company class
#Entity
#Table(name = "company")
#Setter
#Getter
public class Company
{
#Id
#GeneratedValue
#Column(name = "company_id")
private Long id;
#Column(name = "company_name")
private String companyName;
}
Company Table
company_id company_name
1 Dell
2 Apple
3 Microsoft
Here is how I am creating the Employee object
Employee emp = new Employee();
emp.setEmployeeId(10);
emp.setEmployeeName("Michael");
Company company = new Company();
company.setId(1);
emp.setCompany(company);
employeeRepository.save(emp);
Please, someone, let me know how to link the company class to an employee class rather than saving one more company.
The best solution for me is to lazy load your company with a proxy. To do it with Spring Data JPA, you need to make your company repository extends JpaRepository. That give you access to the method getReferenceById :
Employee emp = new Employee();
emp.setEmployeeId(10);
emp.setEmployeeName("Michael");
emp.setCompany(companyRepository.getReferenceById(1))
employeeRepository.save(emp);
If there is no company for the given id, an EntityNotFoundException is throw.
With a proxy, you avoid the request to the database in most case because Hibernate use its cache for check the existence of the company. But if my memory serves me correctly, Hibernate gonna make a request to the database at each call to a getter of the proxy, except for getId(). So, in your case it's a good solution, but don't use it all the time.
Assuming the Company may have more than one Employee the relation is a ManyToOne, not a OneToOne.
If you want to reference an existing entity, load it instead of creating a new one:
Employee emp = new Employee();
// ...
emp.setCompany(companyRepository.findById(1));
employeeRepository.save(emp);

JPA Entity class which is not mapped to any table

I am using a entity class for mixing two/three table columns in one entity to hold an outcome of SYS_REFCURSOR in oracle
This allows me to have single class which is not mapped to any table but it still is an Entity
#Data
#Entity
#NoArgsConstructor
class EmployeeDetails {
#Id
#Column("emp_id")
String empId;
#Column("job_name")
String jobName;
#Column("dept_name")
String deptName;
//Future requirement
//String updatedBy
}
Now I have an additional requirement, to add who last modified the employee table, I don't want modify the procedure now, the procedure is being re-used in another background procedure and batch jobs.
My question is, is it possible to use #ManyToOne on this class which is obviously not mapped to any table
If not how do avoid manually looping a child array list, is there a ready made option in JPA or spring boot to achieve that.
Or what will be the smartest/recommended way to bring the below Entity into this class
#Data
#Entity
#NoArgsConstructor
#Table(name="app_users")
class AppUsers {
#Id
#Column(name="user_id")
String userId;
#Column
String userName;
}
#Transient, check how this annotation works it will resolve the issue, you need to understand working of #Transient
My spring boot 2.6.2 EntityManager code is as follows
q = em.createStoredProcedureQuery("MY_PROC",EmployeeDetails.class);
q.registerStoredProcedureParameter("OUT_REFC", void.class, ParameterMode.REF_CURSOR);
q.execute();
q.getResultList()
I have modified my class EmployeeDetails as below
#Data
#Entity
#NoArgsConstructor
class EmployeeDetails {
#Id
#Column("emp_id")
String empId;
#Column("job_name")
String jobName;
#Column("dept_name")
String deptName;
#OneToOne
#JoinColumn(
name="user_id",
referencedColumnName="emp_id",
insertable=false,
updatable=false,
nullable=true
)
AppUsers updatedBy;
}
The log prints Hibernate two times one after one as below, first it calls the proc and then it calls the select query, so, I did not wrote that SQL myself, the JPA layer is taking care of it
Hibernate:
{call MY_PROC(?)}
Hibernate:
select
...
...
from app_users
where user_id=?
so, my expectation achieved and I am getting the values

how to map custom sql query to model to load on jsp view in spring

I am beginner in spring. I want to show SQL data to JSP view page.
This is my SQL table
create table customer(
id int primary key,
name varchar(250),
salary int,
manager_id int
)
and I am trying to show data from this query
select m.id, m.name, m.salary, n.name from customer m, customer n where n.id=m.manager_id
So basically from this query, I am trying to show ID int, name varchar, salary int, manager_name varchar.
I have create the entity java class as below
#Entity
#Table(name="customer")
public class Customer{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column
private int id;
#Column
private String name;
#Column(name="manager_id")
private String manager;
#Column(name="salary")
private int salary;
............
............
}
This is the code of my DAO class
Session session= entityManager.unwrap(Session.class);
Query<Employee> query= session.createQuery(<above sql query need to add here?>,Customer.class);
return query.getResultList();
So the issues are,
This SQL query return the data which could not be matched to Customer Entity class. So do I need to create another Entity class for this? Is there any better way?
The above required SQL query is not able to execute. What the correct way to execute custom SQL query?
Regarding your first question: Yes there is better way. you can directly fetch the results in a projection dto class. take a at: https://vladmihalcea.com/the-best-way-to-map-a-projection-query-to-a-dto-with-jpa-and-hibernate/
About your second question: What Do you mean by saying the query does not execute?
Can you give us the Exception/Stacktrace? Did you try to execute the query (sql form of it) physically? Does it run then?

Inject data in json entity with Spring Data REST

I have JPA entity for department:
public class Department {
#Id
#Column(unique = true, nullable = false)
private long id;
#Basic
#Column
#Nationalized
private String name;
#Basic
#Column(length = 400)
#Nationalized
private String branch;
...
}
And REST repository
#RepositoryRestResource(collectionResourceRel = "departments", path = "departments")
public interface DepartmentRestRepository extends PagingAndSortingRepository<Department, Long> {
...
}
Entity's branch field is IDs of entity parent departments separated by space, e.g. 1 2 3.
When I query specific department via /api/departments/ID is it possible to attach to it field like parents with all parent entities queried?
I tryed to add getParents method to entity, but it obviously gave me unneeded parents queries with all entities recursively.
Update 2019.01.17:
As a workaround I splitted Department entity into Department and DepartmentWithParents. I added Department getParents() method to DepartmentWithParents entity and exposed REST API method that returns DepartmentWithParents.
Is there better way?
As a workaround I splitted Department entity into Department and DepartmentWithParents. I added Department getParents() method to DepartmentWithParents entity and exposed REST API method that returns DepartmentWithParents.

HQL join query: Path expected for join

I'm new to hql, I referred to a site to write hql query in Spring Framework, but it throws "Path expected for join!" exception
My query is
"from GaugeCateSelect cs inner join PreferredUrl purl on cs.survey=purl.survey where purl.uuid=:uuid"
I want to connect both table with "survey".
How can I sort it out?
Update
Two tables, names are GaugeCateSelect and PreferredUrl. The "survey" field is common for both table. uuid is in PreferredUrl. I want to get all data from GaugeCateSelect when I pass the uuid to PreferredUrl table. (In short, Pass uuid to PreferredUrl, then find the survey number from PreferredUrl and check the number with GaugeCateSelect table, if exists get all data)
Update 2
There is no primary/foreign key reference relationship between two tables. but common field survey is there
GaugeCateSelect class
class GaugeCateSelect {
private int id;
private String categoryName;
private int posNeg;
private Survey survey; //survey is in foreign key relationship of survey table
//Annotation, getters and setters were removed for easiness.
}
PreferredUrl class
public class PreferredUrl {
private int preferredUrlId;
private String uuid;
private int enabled;
private Survey survey; //survey is in foreign key relationship of survey table
//Annotation, getters and setters were removed for easiness.
}
Maybe you should check the Hibernate version you use as there is a difference when joining unrelated entities as discussed here: https://www.thoughts-on-java.org/how-to-join-unrelated-entities/

Resources