how to fetch data hierarchal data from database in java - java

there is table of employee in database like in this image and use jdbc and java to fetch data from table. expected result also in image.
desired output in image

You can create an Employee class which contains the list of reports as below along with empId and reportingId:
public class Employee {
private String empId;
private String reportingId;
private List<Employee> reports;
public Employee(String empId, String reportingId) {
this.empId = empId;
this.reportingId = reportingId;
this.reports = new ArrayList<>();
}
public String getEmpId() {
return empId;
}
public String getReportingId() {
return reportingId;
}
public List<Employee> getReports() {
return reports;
}
}
// Step 1: Connect to the database
Connection conn = DriverManager.getConnection(connectionString, username, password);
// Step 2: Execute a SELECT statement
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT empId, reportingId FROM employee");
// Step 3: Iterate over the resultset and create a Map of Employee objects
Map<String, Employee> employees = new HashMap<>();
while (rs.next()) {
String empId = rs.getString("empId");
String reportingId = rs.getString("reportingId");
Employee employee = new Employee(empId, reportingId);
employees.put(empId, employee);
}
// Step 4: Iterate over the Map and create the hierarchy of Employee objects
for (Employee employee : employees.values()) {
Employee manager = employees.get(employee.getReportingId());
if (manager != null) {
manager.getReports().add(employee);
}
}
// The hierarchy of Employee objects is now complete
You can then print the hierarchy of Employee objects using a recursive method, like this:
public void printHierarchy(Employee employee, int level) {
for (int i = 0; i < level; i++) {
System.out.print("\t");
}
System.out.println(employee.getEmpId());
for (Employee report : employee.getReports()) {
printHierarchy(report, level + 1);
}
}
Call the printHierarchy method from 101 employee
Output:
101
1013
1012
101222
101223
1011
101101
101102

Related

Spring jdbcTemplate data access and java algorithms

I have one method which must return data in DAO.
Department model:
public class Department implements Serializable {
private Long id;
private String departmentName;
private List<Employees> employeesInThisDepartment;
// getters and setters...
}
Employees model:
public class Employees implements Serializable {
private Long id;
private String department;
private String fullName;
private Date birthday;
private int salary;
// getters and setters...
}
And method in DAO:
#Override
public Department findByDepartmentNameWithEmployees(String departmentName) {
String sql = "select d.id, d.departmentName, e.id, e.fullName, e.department, e.birthday" +
", e.salary from department as d left join employees as e on d.departmentName = e.department " +
"where lower(d.departmentName) = lower(:departmentName)";
Map<String, Object> map = new HashMap<>();
map.put("departmentName", departmentName);
return jdbcTemplate.queryForObject(sql, map, (rs, rowNum) -> {
Department department = new Department();
department.setId(rs.getLong("department.id"));
department.setDepartmentName(rs.getString("department.departmentName"));
department.setEmployeesInThisDepartment(new ArrayList<>());
while (rs.next()){
Employees employees = new Employees();
employees.setId(rs.getLong("employees.id"));
employees.setFullName(rs.getString("employees.fullName"));
employees.setDepartment(rs.getString("employees.department"));
employees.setBirthday(rs.getDate("employees.birthday"));
employees.setSalary(rs.getInt("employees.salary"));
department.getEmployeesInThisDepartment().add(employees);
}
return department;
});
}
This method must return one department with list of all employees who works in this department, but it misses the first employee in the list.
Why is this happening? (SQL part is working correctly, I think that the problem is with the loop?)
Right, problem in the loop. According to docs:
Implementations must implement this method to map each row of data in
the ResultSet.
So you do not need to invoke rs.next(), just remove this loop wrapper and move block
Department department = new Department();
department.setEmployeesInThisDepartment(new ArrayList<>());
outside return jdbcTemplate.queryForObject(sql, map, (rs, rowNum) -> { ... }. I.e.:
Department department = new Department();
department.setEmployeesInThisDepartment(new ArrayList<>());
jdbcTemplate.queryForObject(sql, map, (rs, rowNum) -> {
department.setId(rs.getLong("department.id"));
department.setDepartmentName(rs.getString("department.departmentName"));
Employees employees = new Employees();
employees.setId(rs.getLong("employees.id"));
employees.setFullName(rs.getString("employees.fullName"));
employees.setDepartment(rs.getString("employees.department"));
employees.setBirthday(rs.getDate("employees.birthday"));
employees.setSalary(rs.getInt("employees.salary"));
department.getEmployeesInThisDepartment().add(employees);
});
return department;

Mapping relational DB to a List<Object> each containing a List<Object> using JdbcTemplate

I am using Spring MVC with JdbcTemplate and a MySQL database.
Say I have the following 2 tables :
table_school
ID NAME
table_students
ID NAME ADDRESS SCHOOL_ID
I have a School POJO that has the following class variables :
int id, String name, List<Student> students
Is there a way of retrieving a List with each School object containing the appropriate List of Student objects using JdbcTemplate in one query? I know this is easily achievable using Hibernate but I would like to use JdbcTemplate ..
Many thanks !
Yes, you can fetch all data in 1 query.
Simple example:
class Student {
int id;
String name;
String addr;
Student(int id, String name, String addr) {
this.addr = addr;
this.id = id;
this.name = name;
}
}
class School {
int id;
String name;
List<Student> students = new ArrayList<>();
School(int id, String name) {
this.id = id;
this.name = name;
}
void addStudent(Student s) {
students.add(s);
}
}
/*
* helper method that gets school from map or create if not present
*/
private School getSchool(Map<Integer, School> schoolMap, int id, String name) {
School school = schoolMap.get(id);
if (school == null) {
school = new School(id, name);
schoolMap.put(id, school);
}
return school;
}
// RUN QUERY
String sql =
" select st.ID, st.NAME, st.ADDRESS. s.id, s.name" +
" from table_students st" +
" inner join table_school s on st.school_id = s.id";
final Map<Integer, School> schoolMap = new HashMap<>();
jdbcTemplate.query(sql, new RowCallbackHandler() {
#Override
public void processRow(ResultSet rs) throws SQLException {
int studentId = rs.getInt(1);
String studentName = rs.getString(2);
String studentAddr = rs.getString(3);
int schoolId = rs.getInt(4);
String schoolName = rs.getString(5);
Student student = new Student(studentId, studentName, studentAddr);
getSchool(schoolMap, schoolId, schoolName).addStudent(student);
}
});
One final point regarding fetching performance:
If you expect many records to fetch it is nearly always a good idea to increase jdbc fetch size parameter. So before run query set it on your jdbcTemplate:
jdbcTemplate.setFetchSize(200); // you can experiment with this value
or if you are using spring's JdbcDaoSupport you can use such pattern:
public class MyDao extends JdbcDaoSupport {
....
#Override
protected void initTemplateConfig() {
getJdbcTemplate().setFetchSize(200);
}
}

ParameterizedRowMapper That Maps Object List to Object

I am trying to set the Parent List in a ParameterizedRowMapper how is this written or approached. I have two Objects one for parent and one for children however children contains a ListThe parents for each child are stored in a separate table in the database and the mapping is 1 - many.
The select for the records for the parents will be done in a separate ResultSet. Will the mapping have to be done separately (separate ParameterizedRowMapper), if so how will i have to write the ParameterizedRowMapper this is the major concern how ParameterizedRowMapper is written to accommodate a list items.
ParameterizedRowMapper
public static class ChildrenMapper implements ParameterizedRowMapper<Children>{
public Children mapRow(ResultSet rs, int rowNum) throws SQLException {
Children child = new Children();
child.setFirstName(rs.getString("firstName"));
child.setLastName(rs.getString("lastName"));
//a child can have many Parents or gaurdians
child.setParent(List<Parent>);
return child;
}
}
Based on my research i have found that i need to use ResultSetExtractor, however i have a questions on the use of that. Do i integrate it into the class at the point of setting the Parent? Can someone guide me on how it can be done the correct way
Children.java
Public class Children(){
int cid;
String firstName;
String lastName;
List<Parent>parents;
..
//getters/setters
}
Parent.java
Public class Parent(){
int pid;
String firstName;
String lastName;
..
//setters/getters
}
I will show how to do this for a canonical 1-to-many example, you can adapt it to your vo class / table.
Order class
public class Order {
private Long orderId;
private String user;
private List<LineItem> items;
// Getter / setter omitted
}
Item class
public class LineItem {
private Long lineItemId;
private String product;
private int quantity;
// Getter / setter omitted
}
Use two rowmappers one for each class and then use a result set extractor to convert multiple rows into one order + line items
OrderRepository
public final static RowMapper<Order> orderMapper = ParameterizedBeanPropertyRowMapper.newInstance(Order.class);
public final static RowMapper<LineItem> lineItemMapper = ParameterizedBeanPropertyRowMapper.newInstance(LineItem.class);
public Order findOrderWithItems(Long orderId) {
return jdbcTemplate.query("select * from orders, line_item "
+ " where orders.order_id = line_item.order_id and orders.order_id = ?",
new ResultSetExtractor<Order>() {
public Order extractData(ResultSet rs) throws SQLException, DataAccessException {
Order order = null;
int row = 0;
while (rs.next()) {
if (order == null) {
order = orderMapper.mapRow(rs, row);
}
order.addItem(lineItemMapper.mapRow(rs, row));
row++;
}
return order;
}
}, orderId);
}
public List<Order> findAllOrderWithItmes() {
return jdbcTemplate.query("select * from orders, line_item "
+ " where orders.order_id = line_item.order_id order by orders.order_id",
new ResultSetExtractor<List<Order>>() {
public List<Order> extractData(ResultSet rs) throws SQLException, DataAccessException {
List<Order> orders = new ArrayList<Order>();
Long orderId = null;
Order currentOrder = null;
int orderIdx = 0;
int itemIdx = 0;
while (rs.next()) {
// first row or when order changes
if (currentOrder == null || !orderId.equals(rs.getLong("order_id"))) {
orderId = rs.getLong("order_id");
currentOrder = orderMapper.mapRow(rs, orderIdx++);
itemIdx = 0;
orders.add(currentOrder);
}
currentOrder.addItem(lineItemMapper.mapRow(rs, itemIdx++));
}
return orders;
}
});
}

removing duplicate records in list

Hi while developing one of my web application i am storing the user information in to an ArrayList based on sql query executed, it contain duplicate objects how to remove duplicate objects in list , i already tried some method but it still not working.
This Is My Code Correct me where i am wrong
public ArrayList loadData() throws ClassNotFoundException, SQLException {
ArrayList userList = new ArrayList();
String url = "";
String dbName = "";
String userName = "";
String password = "";
Connection con = null;
Class.forName("org.apache.derby.jdbc.ClientDriver");
con = DriverManager.getConnection(url + dbName, userName, password);
PreparedStatement ps = null;
try {
String name;
String fatherName;
int Id;
String filePath;
int age;
String address;
String query = "SELECT NAME,FATHERNAME,AGE,ADDRESS,ID,FILEPATH FROM USER_INFORMATION ,USER_PHOTO WHERE ID=USER_ID";
ps = con.prepareStatement(query);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
name = rs.getString(1);
fatherName = rs.getString(2);
age = rs.getInt(3);
address = rs.getString(4);
Id = rs.getInt(5);
filePath=rs.getString(6);
/* if(flag)
{
prev=Id;
flag=false;
}
else if(Id==prev)
{
TEMP=TEMP+";"+filePath;
}*/
//PhotoList = PhotoList(Id, con);
UserData list = new UserData();
list.setName(name);
list.setFatherName(fatherName);
list.setAge(age);
list.setAddress(address);
list.setId(Id);
// list.setFilePath(filePath);
userList.add(list);
}
ps.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
}
ArrayList al = new ArrayList();
HashSet hs = new HashSet();
hs.addAll(userList);
al.clear();
al.addAll(hs);
return al;
}
And My Bean Class contant is
public class UserData {
private String name;
private String fatherName;
private int Id;
//private String filePath;
private int age;
private String address;
public UserData()
{
}
public UserData(String name, String fatherName,int Id, int age,String address)
{
this.name = name;
this.fatherName = fatherName;
this.Id = Id;
//this.filePath=filePath;
this.age=age;
this.address=address;
}
//GETTER AND SETTER..
General Idea: Use Set, not List. But you must override hash and equals of the class.
If you want a Collection of objects that does not have a specific order and you don't want duplicates, it's better for you just to use a Set like for example HashSet, or, if in your set the order is important, the TreeSet.
Just remember to override the hash and equals methods.
if you add this to your bean everything should work:
public int hashCode() {
return (name + fatherName+ Id + filePath + age + address).hashCode();
}
public boolean equals(Object obj) {
return ( hashCode() == obj.hashCode() );
}
Your userdata class does not implement equals or hashcode. This means two instances created with the same values will not be counted as duplicates. This is why the set contains duplicates.
For example
UserData u1 = new UserData("Foo", "bar",1, 1,"baz");
UserData u2 = new UserData("Foo", "bar",1, 1,"baz");
u1 and u2 are not considered equal as they are different objects. Adding an equals and hashcode method should fix this. However even better is adarshr's idea of removing dupes in the SQL.
All duplicates must be removed at an SQL level. Your SQL is suggesting that it could be generating duplicate records.
String query = "SELECT NAME,FATHERNAME,AGE,ADDRESS,ID,FILEPATH FROM USER_INFORMATION ,USER_PHOTO WHERE ID=USER_ID";
What does the clause ID = USER_ID mean? Shouldn't you be passing in that value as an input to your query?
Also, is the column ID a primary key? Otherwise, use a where clause that doesn't generate duplicates.

newbie attempt to use Java ArrayList to store ResultSet obtained from database

I have a database server communicating with a Java application server using JDBC. I want to store data from the database ResultSet into Java variables.
Here's my Java class, HRPeople:
public class HRPeople {
public int elements;
public String[] FirstName;
public String[] LastName;
public String[] Email;
public int[] Salary;
}
I currently use this class to store data from ResultSet, as follows:
query = "SELECT first_name, last_name, email, salary FROM HR.Employees where rownum < 6";
rset = stmt.executeQuery(query);
while (rset.next()) {
returnHRdata.FirstName[ii] = rset.getString("first_name");
returnHRdata.LastName[ii] = rset.getString("last_name");
returnHRdata.Email[ii] = rset.getString("email");
returnHRdata.Salary[ii] = rset.getInt("salary");
ii = ii + 1;
}
The problem with the above scenario is that the primitive arrays require me to know the number of rows in the ResultSet so that I can properly initialize those arrays. So what I want to do is use an ArrayList instead. How would I modify the above scenario to do this?
Here's my initial attempt (is this close)? Is HRPeople.java file shown above even used in this scenario?
query = "SELECT first_name, last_name, email, salary FROM HR.Employees where rownum < 6";
rset = stmt.executeQuery(query);
List<HRPeople> returnHRdata = new ArrayList<HRPeople>();
while (rset.next()) {
returnHRdata.FirstName = rset.getString("first_name");
returnHRdata.LastName = rset.getString("last_name");
returnHRdata.Email = rset.getString("email");
returnHRdata.Salary = rset.getInt("salary");
returnHRdata.add;
}
UPDATE 1:
If I add to the code the following,
return returnHRdata;
I get the following error (any idea why?):
myClass.java:213: incompatible types
found : java.util.List<HRPerson>
required: java.util.ArrayList<HRPerson>
return returnHRdata;
^
1 error
You probably want to first define an HRPerson like this:
public class HRPerson {
public String firstName;
public String lastName;
public String email;
public int salary;
}
Then your main code would look like:
query = "SELECT first_name, last_name, email, salary FROM HR.Employees where rownum < 6";
rset = stmt.executeQuery(query);
List<HRPerson> returnHRdata = new ArrayList<HRPerson>();
while (rset.next()) {
HRPerson person = new HRPerson();
person.firstName = rset.getString("first_name");
person.lastName = rset.getString("last_name");
person.email = rset.getString("email");
person.salary = rset.getInt("salary");
returnHRdata.add(person);
}
List<HRPeople> returnHRdata = new ArrayList<HRPeople>();
while (rset.next()) {
HRPeople people = new HRPeople();
people.FirstName = rset.getString("first_name");
people.LastName = rset.getString("last_name");
people.Email = rset.getString("email");
people.Salary = rset.getInt("salary");
returnHRdata.add(people);
}
You can improve this code by using a lowerCase letter for your first char of your fields and using getters and setters to access them.
Convert this:
public class HRPeople {
public int elements;
public String[] FirstName;
public String[] LastName;
public String[] Email;
public int[] Salary;
}
to:
public class HRPerson {
public String firstName;
public String lastName;
public String email;
public int salary;
}
and:
List<HRPerson> people = new ArrayList<HRPerson>();
Now it should be easy:
while (rset.next()) {
HRPerson person = new HRPerson();
returnHRdata.firstName = rset.getString("first_name");
returnHRdata.lastName = rset.getString("last_name");
returnHRdata.email = rset.getString("email");
returnHRdata.salary = rset.getInt("salary");
people.add(person);
}
Close...
while (rset.next()) {
HRPeople person = new HRPeople();
person.setFirstName(rset.getString("first_name"));
person.setLastName(rset.getString("last_name"));
person.setEmail(rset.getString("email"));
person.setSalary(rset.getInt("salary"));
returnHRdata.add(person);
}
You of course must define the setXXXX methods on the HRPerson class. Oh yeah, and do what Thomasz suggested.
create a class HRPeople, which has firstname, lastname.... attributes, and declare getter, setters method.
then:
List<HRPeople> returnHRdata = new ArrayList<HRPeople>();
HRPeople people = null;
while (rset.next()) {
people = new HRPeople();
people.setFirstName( rset.getString("first_name"));
people.setLastName (rset.getString("last_name"));
...
returnHRdata.add(people);
}
Instead of storing an array of each property in your object, make a single object to describe a given entity in the table.
class HRPerson {
String firstName;
String lastName;
String email;
Integer salary;
}
Create a list of this type, allowing you to store the results.
List<HRPerson> hrPeople = new ArrayList<HRPerson>();
while(rset.next()) {
HRPerson person = new HRPerson();
person.firstName = rset.getString("first_name");
person.lastName = rset.getString("last_name");
person.email = rset.getString("email");
person.salary = rset.getInt("salary");
hrPeople.add(person);
}
Finally, fill it by creating new objects for each row in your table.

Categories