Adds Projects and ProjectsTests and ensures robust delete operations of all entities

This commit does these things:
	- Adds Projects and ProjectsTest for basic operations with Project.
	- Ensures that delete operations preserves the database integrity (i.e.
	  no FK constraint exceptions). We do this in several ways:
		- By adding CascadeType.REMOVE in @OneToMany where appropriate (e.g: Projects->ProjectAssignment)
		- By manually setting to NULL orphan entities (e.g: Department->Employee)
		- By manually removing orphan entities when no @OneToMany is available
		  (e.g: Employee->ProjectAssignment)
	- Adds CascadeType.PERSIST in Project->ProjectAssignment to automatically persist ProjectAssignments
	  that were added to a given Project.
	- Refactors tests to avoid repetitive JDBC code that inserts some registers before the test.
parent d8eb7051
......@@ -21,7 +21,7 @@ public class Departments {
}
public void deleteDepartment(Department d) {
// remove first my employees
// unassign employees to this department to preserve DB integrity
for (Employee e: d.getEmployees()) {
e.setDepartment(null);
}
......
package dgpena.siexample.persistence;
import java.util.List;
import javax.persistence.EntityManager;
public class Employees {
......@@ -14,4 +16,20 @@ public class Employees {
this.em.persist(e);
}
public Employee findById(int id) {
return em.find(Employee.class, id);
}
public void deleteEmployee(Employee e) {
// First remove his/her project assignments (in order to preserve database integrity)
List<ProjectAssignment> projectAssignments = this.em.createQuery("SELECT pa FROM ProjectAssignment pa WHERE " +
"pa.employee = :e")
.setParameter("e", e).getResultList();
for (ProjectAssignment pa: projectAssignments) {
em.remove(pa);
}
this.em.remove(e);
}
}
package dgpena.siexample.persistence;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
......@@ -18,7 +20,7 @@ public class Project {
private String name;
@OneToMany(mappedBy="project")
@OneToMany(mappedBy="project", cascade = {CascadeType.REMOVE, CascadeType.PERSIST})
private Set<ProjectAssignment> projectAssignments = new HashSet<>();
public int getId() {
......@@ -43,6 +45,15 @@ public class Project {
return employees;
}
public void addEmployee(Employee e, Date startDate) {
ProjectAssignment pa = new ProjectAssignment();
pa.setProject(this);
pa.setStartDate(startDate);
pa.setEmployee(e);
// the ProjectAssignment is automatically persisted due to CascadeType.PERSIST
}
void internalRemoveProjectAssignment(ProjectAssignment projectAssignment) {
this.projectAssignments.remove(projectAssignment);
......@@ -50,7 +61,8 @@ public class Project {
void internalAddProjectAssignment(ProjectAssignment projectAssignment) {
this.projectAssignments.add(projectAssignment);
}
}
package dgpena.siexample.persistence;
import javax.persistence.EntityManager;
public class Projects {
private EntityManager em;
public Projects(EntityManager em) {
this.em = em;
}
public void addNewProject(Project p) {
em.persist(p);
}
public void deleteProject(Project p) {
// ProjectAssingment related instances are automatically removed due to CascadeType.REMOVE
em.remove(p);
}
public Project findById(int id) {
return em.find(Project.class, id);
}
}
......@@ -44,9 +44,7 @@ public class DepartmentsTest extends SQLBasedTest {
@Test
public void testFindById() throws SQLException {
// insert a department previously with JDBC
Statement statement = jdbcConnection.createStatement();
statement.executeUpdate("INSERT INTO Department(name) values('finanzas')", Statement.RETURN_GENERATED_KEYS);
int deptId = getLastInsertedId(statement);
int deptId = insertADepartment("finanzas");
EntityManager em = emf.createEntityManager();
Departments depts = new Departments(em);
......@@ -60,14 +58,10 @@ public class DepartmentsTest extends SQLBasedTest {
@Test
public void testFindByIdWithEmployees() throws SQLException {
// insert a department previously with JDBC
Statement statement = jdbcConnection.createStatement();
statement.executeUpdate("INSERT INTO Department(name) values('finanzas')", Statement.RETURN_GENERATED_KEYS);
int deptId = getLastInsertedId(statement);
int deptId = insertADepartment("finanzas");
// insert an employee in this department previously with JDBC
statement = jdbcConnection.createStatement();
statement.executeUpdate("INSERT INTO Employee(name, department_id) values('pepe', "+deptId+")", Statement.RETURN_GENERATED_KEYS);
int empId = getLastInsertedId(statement);
int empId = insertAnEmployeeInADepartment(deptId);
EntityManager em = emf.createEntityManager();
Departments depts = new Departments(em);
......@@ -82,9 +76,7 @@ public class DepartmentsTest extends SQLBasedTest {
@Test
public void testUpdateDepartment() throws SQLException {
// insert a department previously with JDBC
Statement statement = jdbcConnection.createStatement();
statement.executeUpdate("INSERT INTO Department(name) values('finanzas')", Statement.RETURN_GENERATED_KEYS);
int deptId = getLastInsertedId(statement);
int deptId = insertADepartment("finanzas");
EntityManager em = emf.createEntityManager();
Departments depts = new Departments(em);
......@@ -95,7 +87,7 @@ public class DepartmentsTest extends SQLBasedTest {
em.getTransaction().commit();
// check in the DB using JDBC
statement = jdbcConnection.createStatement();
Statement statement = jdbcConnection.createStatement();
ResultSet rs = statement.executeQuery("SELECT * FROM Department d where d.id = "+deptId);
rs.next();
assertEquals("contabilidad", rs.getString("name"));
......@@ -105,9 +97,7 @@ public class DepartmentsTest extends SQLBasedTest {
@Test
public void testDeleteDepartment() throws SQLException {
// insert a department previously with JDBC
Statement statement = jdbcConnection.createStatement();
statement.executeUpdate("INSERT INTO Department(name) values('finanzas')", Statement.RETURN_GENERATED_KEYS);
int deptId = getLastInsertedId(statement);
int deptId = insertADepartment("finanzas");
EntityManager em = emf.createEntityManager();
Departments depts = new Departments(em);
......@@ -118,7 +108,7 @@ public class DepartmentsTest extends SQLBasedTest {
em.getTransaction().commit();
// check in the DB using JDBC
statement = jdbcConnection.createStatement();
Statement statement = jdbcConnection.createStatement();
ResultSet rs = statement.executeQuery("SELECT COUNT(*) as total FROM Department d where d.id = "+deptId);
rs.next();
assertEquals(0, rs.getInt("total"));
......@@ -127,14 +117,12 @@ public class DepartmentsTest extends SQLBasedTest {
@Test
public void testDeleteDepartmentWithEmployees() throws SQLException {
// insert a department previously with JDBC
Statement statement = jdbcConnection.createStatement();
statement.executeUpdate("INSERT INTO Department(name) values('finanzas')", Statement.RETURN_GENERATED_KEYS);
int deptId = getLastInsertedId(statement);
int deptId = insertADepartment("finanzas");
// insert an employee in this department previously with JDBC
statement = jdbcConnection.createStatement();
statement.executeUpdate("INSERT INTO Employee(name, department_id) values('pepe', "+deptId+")", Statement.RETURN_GENERATED_KEYS);
int empId = getLastInsertedId(statement);
insertAnEmployeeInADepartment(deptId);
Statement statement;
EntityManager em = emf.createEntityManager();
Departments depts = new Departments(em);
......@@ -151,7 +139,6 @@ public class DepartmentsTest extends SQLBasedTest {
assertEquals(0, rs.getInt("total"));
}
@Test
public void testFindAllDepartments() throws SQLException {
// insert a department previously with JDBC
......@@ -182,4 +169,15 @@ public class DepartmentsTest extends SQLBasedTest {
assertTrue(namesToTest.isEmpty());
}
private int insertADepartment(String name) throws SQLException {
// insert a department previously with JDBC
Statement statement = jdbcConnection.createStatement();
statement.executeUpdate("INSERT INTO Department(name) values('"+name+"')", Statement.RETURN_GENERATED_KEYS);
return getLastInsertedId(statement);
}
private int insertAnEmployeeInADepartment(int deptId) throws SQLException {
Statement statement = jdbcConnection.createStatement();
statement.executeUpdate("INSERT INTO Employee(name, department_id) values('pepe', "+deptId+")", Statement.RETURN_GENERATED_KEYS);
return getLastInsertedId(statement);
}
}
......@@ -19,9 +19,7 @@ public class EmployeesTest extends SQLBasedTest {
@Test
public void testAddNewEmployee() throws SQLException {
// insert a department previously with JDBC
Statement statement = jdbcConnection.createStatement();
statement.executeUpdate("INSERT INTO Department(name) values('finanzas')", Statement.RETURN_GENERATED_KEYS);
int deptId = getLastInsertedId(statement);
int deptId = insertADepartment();
EntityManager em = emf.createEntityManager();
......@@ -47,7 +45,7 @@ public class EmployeesTest extends SQLBasedTest {
int employeeId = e.getId();
statement = jdbcConnection.createStatement();
Statement statement = jdbcConnection.createStatement();
ResultSet res = statement.executeQuery("SELECT * from Employee where id = "+employeeId);
res.next();
assertEquals(deptId, res.getInt("department_id"));
......@@ -56,4 +54,55 @@ public class EmployeesTest extends SQLBasedTest {
}
@Test
public void testDeleteEmployeeWithProjectAssignment() throws SQLException {
// insert an employee with JDBC
int employeeId = insertAnEmployee();
// create a project
int projectId = insertAProject();
// assign the employee to the project (which should be removed due to CascadeType.REMOVE
// in Project.projectAssignments)
Statement statement = jdbcConnection.createStatement();
statement.executeUpdate("INSERT INTO ProjectAssignment(project_id, employee_id) values("+projectId+", "
+employeeId+")", Statement
.RETURN_GENERATED_KEYS);
EntityManager em = emf.createEntityManager();
Employees employees = new Employees(em);
Employee e = employees.findById(employeeId);
em.getTransaction().begin();
employees.deleteEmployee(e);
em.getTransaction().commit();
statement = jdbcConnection.createStatement();
ResultSet rs = statement.executeQuery("SELECT COUNT(*) as total FROM Employee e where e.id = "+employeeId);
rs.next();
assertEquals(0, rs.getInt("total"));
}
private int insertADepartment() throws SQLException {
Statement statement = jdbcConnection.createStatement();
statement.executeUpdate("INSERT INTO Department(name) values('finanzas')", Statement.RETURN_GENERATED_KEYS);
return getLastInsertedId(statement);
}
private int insertAnEmployee() throws SQLException {
Statement statement = jdbcConnection.createStatement();
statement.executeUpdate("INSERT INTO Employee(name) values('pepe')", Statement.RETURN_GENERATED_KEYS);
return getLastInsertedId(statement);
}
private int insertAProject() throws SQLException {
Statement statement = jdbcConnection.createStatement();
statement.executeUpdate("INSERT INTO Project(name) values('our best project')", Statement
.RETURN_GENERATED_KEYS);
return getLastInsertedId(statement);
}
}
package dgpena.siexample.persistence;
import static org.junit.Assert.assertEquals;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;
import javax.persistence.EntityManager;
import org.junit.Test;
public class ProjectsTest extends SQLBasedTest {
@Test
public void testAddNewProject() throws SQLException {
EntityManager em = emf.createEntityManager();
Projects projects = new Projects(em);
Project p = new Project();
p.setName("Our best project");
em.getTransaction().begin();
projects.addNewProject(p);
em.getTransaction().commit();
int projectId = p.getId();
Statement statement = jdbcConnection.createStatement();
ResultSet res = statement.executeQuery("SELECT COUNT(*) as total from Project where id = "+projectId);
res.next();
assertEquals(1, res.getInt("total"));
}
@Test
public void testAddEmployeeToProject() throws SQLException {
// insert a project previously with JDBC
int projectId = insertAProject();
// insert an employee previously with JDBC
int employeeId = insertAnEmployee();
EntityManager em = emf.createEntityManager();
Projects projects = new Projects(em);
Project p = projects.findById(projectId);
Employees employees = new Employees(em);
Employee e = employees.findById(employeeId);
em.getTransaction().begin();
p.addEmployee(e, new Date());
em.getTransaction().commit();
// ensure that a ProjectAssignment has been created
Statement statement = jdbcConnection.createStatement();
ResultSet res = statement.executeQuery("SELECT COUNT(*) as total from ProjectAssignment where project_id = " +
""+projectId+" and employee_id = "+employeeId);
res.next();
assertEquals(1, res.getInt("total"));
}
@Test
public void testCreateProjectAssignment() throws SQLException {
// insert a project previously with JDBC
int projectId = insertAProject();
// insert an employee previously with JDBC
int employeeId = insertAnEmployee();
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Project p = new Projects(em).findById(projectId);
Employee e = new Employees(em).findById(employeeId);
ProjectAssignment pa = new ProjectAssignment();
pa.setProject(p); // pa is automatically added to the Project.projectAssignments collection
pa.setEmployee(e);
pa.setStartDate(new Date());
// the ProjectAssignment is automatically persisted due to CascadeType.PERSIST present in Project.projectAssignments
em.getTransaction().commit();
// ensure that a ProjectAssignment has been created using JDBC
Statement statement = jdbcConnection.createStatement();
ResultSet res = statement.executeQuery("SELECT COUNT(*) as total from ProjectAssignment where project_id = " +
""+projectId+" and employee_id = "+employeeId);
res.next();
assertEquals(1, res.getInt("total"));
}
@Test
public void testDeleteProject() throws SQLException {
// insert a project previously with JDBC
int projectId = insertAProject();
// insert an employee previously with JDBC
int employeeId = insertAnEmployee();
// assign the employee to the project (which should be removed due to CascadeType.REMOVE
// in Project.projectAssignments)
Statement statement = jdbcConnection.createStatement();
statement.executeUpdate("INSERT INTO ProjectAssignment(project_id, employee_id) values("+projectId+", "
+employeeId+")", Statement
.RETURN_GENERATED_KEYS);
EntityManager em = emf.createEntityManager();
Projects projects = new Projects(em);
Project p = projects.findById(projectId);
em.getTransaction().begin();
projects.deleteProject(p);
em.getTransaction().commit();
// ensure that project doesn't exist using JDBC
statement = jdbcConnection.createStatement();
ResultSet res = statement.executeQuery("SELECT COUNT(*) as total from Project where id = " +
""+projectId);
res.next();
assertEquals(0, res.getInt("total"));
}
@Test
public void testGetEmployees() throws SQLException {
// insert a project previously with JDBC
int projectId = insertAProject();
// insert an employee previously with JDBC
int employeeId = insertAnEmployee();
// assign the employee to the project (which should be removed due to CascadeType.REMOVE
// in Project.projectAssignments)
Statement statement = jdbcConnection.createStatement();
statement.executeUpdate("INSERT INTO ProjectAssignment(project_id, employee_id) values("+projectId+", "
+employeeId+")", Statement
.RETURN_GENERATED_KEYS);
}
private int insertAProject() throws SQLException {
Statement statement = jdbcConnection.createStatement();
statement.executeUpdate("INSERT INTO Project(name) values('our best project')", Statement
.RETURN_GENERATED_KEYS);
return getLastInsertedId(statement);
}
private int insertAnEmployee() throws SQLException {
Statement statement = jdbcConnection.createStatement();
statement.executeUpdate("INSERT INTO Employee(name) values('pepe')", Statement
.RETURN_GENERATED_KEYS);
return getLastInsertedId(statement);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment