Tuesday 6 December 2011

Remove all .svn folders in Windows XP

It has been a tedious job to remove all the .svn folders in a project checked out from SVN repository. Thanks to http://www.iamatechie.com/remove-all-svn-folders-in-windows-xp-vista/, we now have an easy way.

Create a blank svnresistry.reg file (can be any name with .reg extension) on your desktop, edit it, and copy the following code snippet as its content.

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\DeleteSVN]
@="Delete SVN Folders"
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\DeleteSVN\command]
@="cmd.exe /c \"TITLE Removing SVN Folders in %1 && COLOR 9A && FOR /r \"%1\" %%f IN (.svn) DO RD /s /q \"%%f\" \""

Double click the reg file to execute it.

Then you can right click on the project folder, you will see a 'Delete SVN Folders' menu.


Just clicking on this menu will remove all the 'svn' folders under this directory recursively.

Saturday 3 December 2011

JPA one-to-many many-to-one relationship

many-to-one unidirectional mapping

@Entity
@Table(name="T_MANAGER")
public class Manager {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="MANA_ID")
    private int id;
    
    @Column(name="MANA_NAME")
    private String name;
}

@Entity
@Table(name="T_EMPLOYEE")
public class Employee {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="EMPL_ID")
    private int id;
    
    @Column(name="EMPL_NAME")
    private String name;

    @ManyToOne(cascade=CascadeType.PERSIST)
    private Manager manager;
}

Domain model


T_EMPLOYEE.MANAGER_MANA_ID is the foreign key referenced to T_MANAGER.MANA_ID

MANAGER_MANA_ID is the default foreign key column name. It is derived from class name + ‘_’ + primary key name (‘MANAGER’ + ‘_’+’MANA_ID’)

Test:

@PersistenceContext(unitName="unit")
private EntityManager em;

private void save(){
    Manager manager1 = new Manager("John");
    Employee employee1 = new Employee("Bob");
    Employee employee2 = new Employee("Tim");
    Employee employee3 = new Employee("Mary");
    employee1.setManager(manager1);
    employee2.setManager(manager1);
    employee3.setManager(manager1);
    
    Manager manager2 = new Manager("Robert");
    Employee employee4 = new Employee("Tom");
    Employee employee5 = new Employee("Alex");
    employee4.setManager(manager2);
    employee5.setManager(manager2);
    em.persist(employee1);
    em.persist(employee2);
    em.persist(employee3);
    em.persist(employee4);
    em.persist(employee5);
}
Result:

T_MANAGER


T_EMPLOYEE


Specify foreign key column name

@OneToOne(cascade={CascadeType.PERSIST, 
    CascadeType.MERGE, CascadeType.REMOVE}, 
    optional=false, fetch=FetchType.EAGER)
@JoinColumn(name="F_ADDR_ID", referencedColumnName="ADDR_ID")
private Address address;

Domain model


The name attribute of @JoinColumn (‘F_MANA_ID’) specifies the foreign key column name.

many-to-one bidirectional mapping

@Entity
@Table(name="T_MANAGER")
public class Manager {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="MANA_ID")
    private int id;
    
    @Column(name="MANA_NAME")
    private String name;
    
    @OneToMany(cascade={CascadeType.ALL}, mappedBy="manager")
    private Set<Employee> employees;
}

@Entity
@Table(name="T_EMPLOYEE")
public class Employee {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="EMPL_ID")
    private int id;
    
    @Column(name="EMPL_NAME")
    private String name;

    @ManyToOne(cascade=CascadeType.PERSIST)
    @JoinColumn(name="F_MANA_ID")
    private Manager manager;
}

Domain model

Same as unidirectional mapping


Test:

@PersistenceContext(unitName="unit")
private EntityManager em;

private void save(){
    Manager manager1 = new Manager("John");
    Employee employee1 = new Employee("Bob");
    Employee employee2 = new Employee("Tim");
    Employee employee3 = new Employee("Mary");
    Set<Employee> employees1 = new HashSet<Employee>();
    employee1.setManager(manager1);
    employee2.setManager(manager1);
    employee3.setManager(manager1);
    employees1.add(employee1);
    employees1.add(employee2);
    employees1.add(employee3);
    manager1.setEmployees(employees1);
    
    Manager manager2 = new Manager("Robert");
    Employee employee4 = new Employee("Tom");
    Employee employee5 = new Employee("Alex");
    Set<Employee> employees2 = new HashSet<Employee>();
    employees2.add(employee4);
    employees2.add(employee5);
    employee4.setManager(manager2);
    employee5.setManager(manager2);
    manager2.setEmployees(employees2);
    
    em.persist(manager1);
    em.persist(manager2);
}

Result:

Same as unidirectional mapping

T_MANAGER


T_EMPLOYEE


Retrieving the employees of a manager returns null.

Manager manager = em.find(Manager.class, 1);
System.out.println(manager.getEmployees());

This is because in a one-to-many relationship, the default fetch type at ONE side is LAZY.

@OneToMany(cascade={CascadeType.ALL}, mappedBy="manager", 
           fetch=FetchType.EAGER)
private Set<Employee> employees;

Change the fetch type to EAGER, and we are able to retrieve the employees of a manager.

Add a new employee to a manager

Manager manager = em.find(Manager.class, 1);
Employee emp = new Employee("Adam");
emp.setManager(manager);
manager.getEmployees().add(emp);
em.merge(manager);

Result:


Update an existing employee of a manager

Manager manager = em.find(Manager.class, 1);
Employee employee = manager.getEmployees().iterator().next();
employee.setName("Josh");
em.merge(manager);

Result:



Delete an existing employee of a manager

Manager manager = em.find(Manager.class, 1);
Set<Employee> employees= manager.getEmployees();
for (Employee emp: employees){
    if ("Bob".equalsIgnoreCase(emp.getName())){
        employees.remove(emp);
        break;
    }
}
em.merge(manager);

Result:


Bob is not deleted! We can see that simply removing the object from the set won’t actually remove the row from the database. So in this case, we need to invoke em.remove() to delete the row.

Manager manager = em.find(Manager.class, 1);
Set<Employee> employees= manager.getEmployees();
for (Employee emp: employees){
    if ("Bob".equalsIgnoreCase(emp.getName())){
        employees.remove(emp);
        em.remove(emp);
        break;
    }
}
em.merge(manager);

Result: