Monday, September 3, 2007

Hibernate: Annotation one-to-many/many-to-one

Bidirectonal one-to-many/many-to-one association

Hibernate Doc (Chap 8.4.1)

::Relationship::
person(many) <-> address(one)
- person A and person B live in address AA

::DB Schema::
person(personId, addressId)
address(addressId)


::Java Operation::
person.getAddress();
address.getPeople();

::Annotation::

@Entity
@Table(name="PERSON")
public class Person {
   
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name="personId")
  private int id;
   
  @ManyToOne
  @JoinColumn(name="addressId")     // inverse = false
  private Address address;
}


@Entity
@Table(name = "ADDRESS")
public class Address {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "addressId")
  private int id;

  @OneToMany(mappedBy="address")  // pointing Person's address field
  @Column(name="personId")    // inverse=true
  private Set<Person> people;
}



::Generated SQL::

[Association Mapping List]

Hibernate: Annotation many-to-many (join table)

Unidirectonal many-to-many (join table)) association

Hibernate Doc (Chap 8.3.4)


::Relationship::
person(many) -> address(many)

::DB Schema::
person(personId)
address(addressId)
personaddress(personId, addressId)

::Java Operation::
person.getAddresses();

::Annotation::

@Entity
@Table(name = "PERSON")
public class Person {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "personId")
  private int id;

  @ManyToMany
  @JoinTable(name = "PersonAddress",
    joinColumns = {
      @JoinColumn(name="personId", unique = true)           
    },
    inverseJoinColumns = {
      @JoinColumn(name="addressId")
    }
  )
  private Set<Address> addresses;
}  


@Entity
@Table(name = "ADDRESS")
public class Address {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "addressId")
  private int id;
}



::Generated SQL::
- person.getAddresses();

select addresses0_.personId as personId1_, addresses0_.addressId as addressId1_, address1_.addressId as addressId3_0_ from PersonAddress addresses0_ left outer join ADDRESS address1_ on addresses0_.addressId=address1_.addressId where addresses0_.personId=?

[Association Mapping List]

Hibernate: Annotation one-to-one (join table)

Unidirectonal one-to-one (join table) association

Hibernate Doc (Chap 8.3.3)

::Relationship::
person(one) -> address(one)

::DB Schema::
person(personId)
address(addressId)
personaddress(personId, addressId)

::Java Operation::
person.getAddress();

::Annotation::

@Entity
@Table(name = "PERSON")
@Entity
@Table(name = "PERSON")
public class Person {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "personId")
  private int id;

  @OneToOne(optional=true)
  @JoinTable(name="PersonAddress",
    joinColumns = {
      @JoinColumn(name="personId", unique = true)           
    },
    inverseJoinColumns = {
      @JoinColumn(name="addressId")
    }     
  )
  private Address address;
}


@Entity
@Table(name = "ADDRESS")
public class Address {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "addressId")
  private int id;  
}



::Generated SQL::
- person.getAddress();

select person0_.personId as personId2_1_, person0_1_.addressId as addressId3_1_, address1_.addressId as addressId4_0_ from PERSON person0_ left outer join PersonAddress person0_1_ on person0_.personId=person0_1_.personId left outer join ADDRESS address1_ on person0_1_.addressId=address1_.addressId where person0_.personId=?

[Association Mapping List]

Hibernate: Annotation many-to-one (join table)

Hibernate Doc (Chap 8.3.2)



::Relationship::
person(many) -> address(one)

ex) person A and person B live in address AA

::DB Schema::
person (personId)
addres (addressId)
personAddress (personId, addressId)

::Java Operation::
person.getAddress();


::Annotation::

@Entity
@Table(name = "PERSON")
public class Person {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "personId")
  private int id;

  @ManyToOne(optional=true)
  @JoinTable(name="PersonAddress",
    joinColumns = {
      @JoinColumn(name="personId", unique = true)           
    },
    inverseJoinColumns = {
      @JoinColumn(name="addressId")
    }     
  )
  private Address address;
}


@Entity
@Table(name = "ADDRESS")
public class Address {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "addressId")
  private int id;
}



::Generated SQL::
- person.getAddress();

select person0_.personId as personId2_1_,
person0_1_.addressId as addressId3_1_,
address1_.addressId as addressId4_0_
from PERSON person0_ left outer join PersonAddress person0_1_ on person0_.personId=person0_1_.personId
left outer join ADDRESS address1_ on person0_1_.addressId=address1_.addressId
where person0_.personId=?

[Association Mapping List]

Hibernate: Annotation one-to-many( join table)

Unidirectonal one-to-many (join table) association

Hibernate Doc (Chap 8.3.1)


::Relationship::
person(one) -> address(many)

::Java Operation::
person.getAddresses();


::Annotation::


@Entity
@Table(name = "PERSON")
public class Person {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "personId")
  private int id;

  @OneToMany
  @JoinTable(name = "PersonAddress",
    joinColumns = {
      @JoinColumn(name="personId", unique = true)           
    },
    inverseJoinColumns = {
      @JoinColumn(name="addressId")
    }
  )
  private Set<Address> addresses;
}


@Entity
@Table(name = "ADDRESS")
public class Address {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "addressId")
  private int id;
}



::Generated SQL::
- person.getAddresses();
select addresses0_.personId as personId1_, addresses0_.addressId as addressId1_, address1_.addressId as addressId3_0_ from PersonAddress addresses0_ left outer join ADDRESS address1_ on addresses0_.addressId=address1_.addressId where addresses0_.personId=?

[Association Mapping List]

Hibernate: Annotation one-to-many (foreign-key)

Hibernate Doc (Chap 8.2.3)

::Relationship::
person(one) -> address(many)

::DB Schema::
person( personId )
address( addressId, personId )

::Java Operation::
person.getAddresses();

::Annotation::
@Entity
@Table(name="PERSON")
public class Person {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="personId")
private int id;

@OneToMany
@JoinColumn(name="personId") 
private Set <Address> addresses;
}

@Entity
@Table(name = "ADDRESS")
public class Address {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "addressId")
private int id;
}

::Generated SQL (mysql5.0)::
[Association Mapping List]

Monday, July 2, 2007

Java Collection finder methods(spring & ruby style)

Using call-back interface(spring way), I wrote finder methods(block call method in ruby).
I hope this closure-style finding methods provide more human readable sourcecode instead of for-looping.

I've needed to search object(s) in List. In the first place, I repeated for-loops to get objects and check whether it matches criteria. Unfortunately, it was not clean-looking-sorucecode for me.

Unfortunately, only final variables are allowed in callback implementation.

Sample Usage(Junit style)

public class SearcherTest {

private List<Person> people;
private Person p1 = new Person("foo", 1);
private Person p2 = new Person("bar", 2);
private Person p3 = new Person("baz", 3);
private CollectionSearcher<Person> searcher;

@Before
public void setUp() {
people = new ArrayList<Person>();
people.add(p1);
people.add(p2);
people.add(p3);

searcher = new CollectionSearcher<Person>(people);
}


@Test
public void testFind() {
Person result = searcher.find(new SearchStrategy<Person>() {
public boolean isEqual(Person person) {
return person.getName().equals("bar");
}
});

assertSame(p2, result);
}

@Test
public void testFindAll() {
List<Person> result = searcher.findAll(new SearchStrategy<Person>() {
public boolean isEqual(Person person) {
return person.getName().startsWith("b");
}
});

assertEquals(2, result.size());
assertSame(p2, result.get(0));
assertSame(p3, result.get(1));
}

@Test
public void testCollect() {
List<Person> result = searcher.collect(new CollectStrategy<Person>() {
public Person compare(Person person) {
if (person.getId() > 2) {
return person;
}
return null;
}
});

assertEquals(1, result.size());
assertEquals(3, result.get(0).getId());
}

@Test
public void testIndexOf() {
int index = searcher.indexOf(new SearchStrategy<Person>() {
public boolean isEqual(Person person) {
return person.getName().equals("baz");
}
});

assertEquals(2, index);
}

@Test
public void testContains() {
boolean result = searcher.contains(new SearchStrategy<Person>() {
public boolean isEqual(Person person) {
return person.getName().equals("baz");
}
});
assertTrue(result);

result = searcher.contains(new SearchStrategy<Person>() {
public boolean isEqual(Person person) {
return person.getName().equals("foobar");
}
});
assertFalse(result);
}


static class Person {
private String name;
private int id;


public Person(String name, int id) {
this.name = name;
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getId() {
return id;
}

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



Implemenatation


public class CollectionSearcher<E> {
private Collection<E> collection;

public CollectionSearcher() {
}

public CollectionSearcher(Collection<E> collection) {
this.collection = collection;
}

/**
* return the first element that given strategy returns true
*
* @param strategy
* @return
*/
public E find(SearchStrategy<E> strategy) {
for (E entry : collection) {
if (strategy.isEqual(entry)) return entry;
}
return null;
}

/**
* returns all element that given strategy returns true
*
* @param strategy
* @return
*/
public List<E> findAll(SearchStrategy<E> strategy) {
List<E> results = new ArrayList<E>();
for (E entry : collection) {
if (strategy.isEqual(entry)) results.add(entry);
}
return results;
}

/**
* return list of elements that strategy returns
* if strategy returns null, then it won't be in the list
*
* @param strategy
* @return
*/
public List<E> collect(CollectStrategy<E> strategy) {
List<E> results = new ArrayList<E>();
for (E entry : collection) {
E result = strategy.compare(entry);
if (result != null) results.add(result);
}
return results;
}

/**
* returns the first index of element that strategy returns true, or -1 if none of the element satisfies the strategy
*
* @param strategy
* @return
*/
public int indexOf(SearchStrategy<E> strategy) {
int index = 0;
for (E entry : collection) {
if (strategy.isEqual(entry)) return index;
index++;
}
return -1;
}

/**
* returns true if the collection has an element that satisfies given strategy
* @param strategy
* @return
*/
public boolean contains(SearchStrategy<E> strategy) {
for (E entry : collection) {
if (strategy.isEqual(entry)) return true;
}
return false;
}


public Collection<E> getCollection() {
return collection;
}

public void setCollection(Collection<E> collection) {
this.collection = collection;
}
}


Search Strategies

public interface CollectStrategy<T> {
T compare(T object);
}

public interface SearchStrategy<T> {
/**
* Returns true if the given object satsfies criteria
* @param object
* @return
*/
boolean isEqual(T object);
}