Wednesday 19 May 2010

Regexp for UK Post Code

Recently was looking UK Post Code RegExp. Found it on StackOverflow. It turned out that there was official regexp published by UK government. Isn't that amassing? :)

Thursday 11 March 2010

Mapping self-referencing relation with additional property in joing table

I have been solving an interesting problem recently. Mapping self-referencing entity in JPA using Hibernate as a persistent provider is not trivial task.
It becomes even less trivial if additional properties are needed to be mapped to joining table.

Let's say there is People entity and it has friends. Each friend can be trustable or not.

The simple data model for this relation can be as follow:

people table
_____________
id | pk
name | text
phone | number


friends table
_______________________________________
people_id | pk, fk -> peoples.id
friend_people_id | pk, fk -> peoples.id
trustable | boolean


Java POJO's will look like:

@Entity
@Table("people")
public class People {
private long id;
private String name;
private int phone;

private Set friends;

@OneToMany(mappedBy = "people", fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
public Set getFriends() {
return friends;
}

public void setFriends(Set friends) {
this.friends = friends;
}

public void addFriend(Friend friend) {

if (!friends.contains(friend)) {
friends.add(friend);
}
}

....
@Id
public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}
...
}


@Entity
@Table(name="friends")
public class Friend {
private FriendPk pk;
private People people;
private People friend;

@EmbeddedId
public FriendPk getPk() {
return pk;
}

public void setPk(FriendPk pk) {
this.pk = pk;
}

@ManyToOne
@JoinColumn(name = "people_id", referencedColumnName="id", insertable = false, updatable = false)
public People getPeople() {
return people;
}

public void setPeople(People people) {
this.people = people;
}

@ManyToOne
@JoinColumn(name = "friend_people_id", referencedColumnName="id", insertable = false, updatable = false)
public People getFriend() {
return friend;
}

...
}


public class FriendPk implements Serializable {
private static final long serialVersionUID = 1L;
private long people_id;
private long friend_people_id;

public FriendPk() {
super();
}

public FriendPk(long peopleId, long freindPeopleId) {
this.people_id = peopleId;
this.friend_people_id = freindPeopleId;
}

public long getPeople_id() {
return people_id;
}

public void setPeople_id(long peopleId) {
people_id = peopleId;
}

public long getFriend_people_id() {
return friend_people_id;
}

public void setFriend_people_id(long friendPeopleId) {
friend_people_id = friendPeopleId;
}
}


To create a new friend the following code should be run inside a transaction

// load people
find People people1 = getEntityManager().find(People.class, id1);
find People people2 = getEntityManager().find(People.class, id2);


final Friend friend = new Friend();
friend.setPk(new FriendPk(people1.getId(), people2.getId()));
friend.setPeople(people1);
friend.setFriend(people2);
friend.setTrustable(true);
people1.addFriend(friend);


This code creates a new relation from people1 to people2. If symmetry is needed the following code should be added

final Friend reverseFriend = new Friend();
reverseFriend .setPk(new FriendPk(people2.getId(), people1.getId()));
reverseFriend .setPeople(people2);
reverseFriend .setFriend(people1);
reverseFriend .setTrustable(true);
people2.addFriend(reverseFriend);