JavaScript Loaders

Showing posts with label hibernate. Show all posts
Showing posts with label hibernate. Show all posts

Thursday, March 3, 2011

Persistence with JPA and Hibernate using Guice 3.0 and guice-persist

Why do I like Google frameworks? Because they are academic-like: elegant, concise, focused, open to extension so they evolve gradually and naturally. Why I don't like Google frameworks? Because they are academic-like: barely documented, lack in visual design and appearance.

Google Guice is no exception. It's been around probably as long as Spring. Anyone looking for DI framework must give it a shot. But even today you hear Spring not Guice when people talk DI.

Using JPA with Spring before I firmly decided to stick with Guice this time. I have simple back-end program: no web, no application server (PostgreSQL database and Hibernate as a JPA 1.0 provider).

I decided to take advantage of the latest JPA support in Guice: guice-persist. Guice 3.0 is required (upgrade from 2.0 if necessary) but Guice jar doesn't contain guice-persist: have both dependencies in your pom.xml when using Maven (updated):
<dependency>
  <groupid>com.google.inject</groupId>
  <artifactid>guice</artifactId>
  <version>3.0</version>
</dependency>
<dependency>
  <groupid>com.google.inject.extensions</groupId>
  <artifactid>guice-persist</artifactId>
  <version>3.0</version>
</dependency>
Without Maven simply follow your regular practices to add jars above to Java classpath.

Existing Guice configuration using module(s) need not change, but add guice-persist module when creating injector. Before:
Injector injector = Guice.createInjector(new MyAppModule());
After:
Injector injector = Guice.createInjector(new MyAppModule(), 
                          new JpaPersistModule("myapp-db"));
myapp-db is a persistence unit defined in persistence.xml placed on classpath (e.g. in Maven project it's in src/main/resources/META-INF directory):

    
        org.hibernate.ejb.HibernatePersistence
        com.example.domain.MyEntity
        true
        
            
            
            
            
            
            
            
        
    

This is JPA 1.0 persistence unit - you should be able to use 2.0 without any problems. I disabled scanning of classpath for entities using exclude-unlisted-classes: all JPA entities should be listed with class element now. The properties are specific to Hibernate and PostgreSQL.

guice-persist works via PersistService that has to be started (initialized). I do it immediately after initializing injector and using injector:

Injector injector = Guice.createInjector(new MyAppModule(), 
                          new JpaPersistModule("myapp-db"));
injector.getInstance(ApplicationInitializer.class);
and
public class ApplicationInitializer {
 @Inject ApplicationInitializer(PersistService service) {
  service.start(); 
  // At this point JPA is started and ready.

  // other application initializations if necessary
 }
}

Persistence unit defined transaction-type="RESOURCE_LOCAL" to have JPA EntityManager created and destroyed for each database transaction. Define both EntityManager and transactions in DAO class with the following Guice annotations:
public class MyAppDAO {
    @Inject
    private EntityManager em;

    @Transactional
    public MyEntity find(long id) {
        return em.find(MyEntity.class, id);
    }

    @Transactional
    public void save(MyEntity entity) {
        em.persist(entity);
    }
}
We injected EntityManager with @com.google.inject.Inject and declared transactions with @com.google.inject.persist.Transactional annotations. Now, each time find or save method called new transaction is started and committed in JPA entity manager. For more details on transaction scope (unit of work) and exception handling see this.

Wrapping it up: there is bare minimum of artifacts/configuration needed on top of standard JPA persistence.xml: new Guice persistence module (provided by guice-persist), persistence service initialization, standard Guice injection of EntityManager, and new @Transactional annotation. Of course, your mileage may vary depending on your transactional (unit of work) needs but it's hard to imagine less configuration and code when implementing data access with JPA and Hibernate.

For completeness I add a Guice module here (it needs no special configuration for guice-persist though, so I have DAO configuration here only):
public class MyAppModule extends AbstractModule {
 
    @Override
    protected void configure() {
        ...
        bind(ISomeDao.class).to(MyDao.class);
    }
}
References:
Using JPA with Guice Persist
Hibernate with JPA Annotations and Guice

Sunday, January 13, 2008

Managing Hierarchical Data (Tree) in Relational Database with JPA

You can't fit an elephant into a matchbox. If hierarchical data model is an elephant then relational database is sure not bigger than a matchbox. I guess if you read this you'd agree that keeping a tree in relational database requires a lot of work. There are at least 2 distinct methods to represent hierarchies (or trees) with relational data: the adjacency list model and the nested set model. I believe that latter is a poor candidate to use with ORM-based technologies due to its set-oriented nature. The adjacency list model is more intuitive to understand and is a good fit for ORM technology. Using both we can introduce some optimization tricks to make our life easier. Below I present an implementation using JPA.

We define a JPA entity Division in accordance with the adjacency list model:

@Entity(name = "Division")
@Table(name = "DIVISION")
@EntityListeners( { HierarchyListener.class } )
public class Division implements IHierarchyElement {
    ...
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "global_id_gen")
@SequenceGenerator(name = "global_id_gen", sequenceName = "GLOBAL_ID_GEN")
@Column(name = "ID")
    public Long getId() {
        return id;
}

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "PARENT_ID")
    public Division getParent() {
        return parent;
}

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "ORG_ID", nullable = false)
public Organization getOrganization() {
  return organization;
}

    @Basic(optional = false)
    @Column(name = "LEVEL", nullable = false)
    public Short getLevel() {
        return level;
    }

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TOP_ID")
    public Division getTop() {
        return top;
}

    public void setLevel(Short theLevel) {
 level = theLevel;
}

    public void setTop(IHierarchyElement theTop) {
 top = (Division) theTop;
}
...
}

for the following table (PostgreSQL flavor):
CREATE TABLE division (
  id INTEGER DEFAULT nextval('global_id_gen') PRIMARY KEY,

  name VARCHAR(128) NOT NULL,
  org_id INTEGER NOT NULL,
  parent_id INTEGER,
  top_id INTEGER NOT NULL,
  level SMALLINT NOT NULL DEFAULT 0,

  UNIQUE (name, org_id),

  CONSTRAINT div_org_fk FOREIGN KEY(org_id)
    REFERENCES organization(id),
  CONSTRAINT div_parent_fk FOREIGN KEY(parent_id)
    REFERENCES division(id),
  CONSTRAINT div_top_fk FOREIGN KEY(top_id)
    REFERENCES division(id),

  CHECK ( (parent_id IS NULL AND level = 0 AND top_id = id) OR
     (parent_id IS NOT NULL AND level > 0 AND top_id <> id)
   )
)
The hierarchical data consists of divisions per organization. Organization may have multiple top divisions. That's why there is an ORG_ID that points to organization this division belongs to. Thus, organization entity serves as a top of the tree of divisions. Table DIVISION uses PARENT_ID column to reference its parent division - so PARENT_ID is nullable (in case of top division whose parent is an organization).

Last piece to the puzzle is the purpose of columns LEVEL and TOP_ID. They are our optimization additions to adjacency list model. LEVEL is an integer that stores level of division in hierarchy: top division (with no parent division and parent organization) has level 0; its children have level 1 and so on. TOP_ID always references top-most division in the hierarchy for its division. If division is top-most (its parent is an organization) then it references itself.

What kind of optimization do we get with LEVEL and TOP_ID? They are not necessary for adjacency list model as PARENT_ID is sufficient. But having more information about tree stored with the data we have more flexibility and easier job in manipulating or reporting on hierarchical data. Thus, I can extract whole sub-tree for any top-most division or answer questions about hierarchy depth using LEVEL with no expensive cursors. It could be that you come up with optimization of your own depending on specific needs.

Back to entity definition in Java. The interface IHierarchyElement is all any hierarchical entity needs to implement and support hierarchical data:

public interface IHierarchyElement {

  IHierarchyElement getParent();

  Short getLevel();

  void setLevel(Short level);

  IHierarchyElement getTop();

  void setTop(IHierarchyElement top);
}

And this is all to it to have an entity support hierarchical model in the relational database. Now we can use one of standard JPA features - callback lifecycle listener class (lookup its usage in the annotations to Division entity above) to maintain data for adjacency list model (for illustration purpose code below is stripped of all error handling):
public class HierarchyListener {

    @PrePersist
    @PreUpdate
    public void setLevelAndTop(IHierarchyElement entity) {

      final IHierarchyElement parent = entity.getParent();

      // set level
      if (parent == null) {
          entity.setLevel((short) 0);
      } else {
          entity.setLevel((short) (parent.getLevel() + 1));
      }

      // set top
      if (parent == null) {
          entity.setTop(entity);
      } else {
          entity.setTop(parent.getTop());
      }
    }
}

This pattern is a combination of specialized interface IHierarchyElement and a callback HierarchyListener class. Using them our goal is to implicitly maintain hierarchical data for JPA entities. When a hierarchical data is shared between many entities in domain model we can claim that this pattern factors out hierarchical aspect of data to focus on business-related semantic in the domain model.

Managing OneToMany relationship in JPA

Now classic book Java Persistence with Hibernate addresses OneToMany relationship in detail. However, I still struggled to find a way to maintain the list of children from the parent entity. The problem appeared while removing children from the list.

Example:
@Entity
@Table(name = "PARENT")
public class Parent implements Serializable {
...
@OneToMany(cascade = { CascadeType.PERSIST,
CascadeType.MERGE },
mappedBy = "parent")
private Set getChildren() {
return children;
}
...
}

@Entity
@Table(name = "CHILD")
public class Child implements Serializable {
...
@ManyToOne

@JoinColumn(name = "PARENTID",
nullable = true)

private Parent getParent() {
return parent;
}
...
}
The problem: I would like to maintain children by manipulating set of children held in parent entity in detached state. After new children are added and/or some of its existing children are removed, parent entity is updated (merged) and with it set of children is updated as well.

Note, that child entity may simply be unassigned from its parent to exist with no parent (nullable = true): by removing child from children list we are not removing child entity from persistent context. This case is more general than one when child is simply removed when unassigned from its parent.

Also note, that child class should implement equals() and hashCode() based on values that uniquely identify each instance. Of course, this is simply JPA best practice.

The following classic solution by the book handles adding new children flawlessly:
@Entity
@Table(name = "PARENT")
public class Parent implements Serializable {
...
@OneToMany(cascade = { CascadeType.PERSIST,
CascadeType.MERGE },
mappedBy = "parent")
private Set getChildren() {
return children;
}

public void addChild(Child theChild) {
theChild.setParent(this);
children.add(theChild);
}
...
}

public class ParentManager {
...
@Transactional(propagation = Propagation.REQUIRED,
readOnly = false)
public void updateParent(Parent parent) {
parentDAO.update(parent);
}

...
}

But if I decide to remove children from the list then this will not have any effect on database as merge operation on parent entity (update) will happily restore removed children. You can search various JPA forums on this topic, e.g.
http://jira.jboss.org/jira/browse/EJBTHREE-941
http://forum.java.sun.com/thread.jspa?threadID=5145294&tstart=210
http://forums.oracle.com/forums/thread.jspa?messageID=1707487

The implementation I propose is not confined to JPA entity classes - it requires coding at higher level of persistent context (where EntityManager is used). This is usually handled at session bean or business manager levels (depending on if I use EJB3 or POJO frameworks):

@Entity
@Table(name = "PARENT")
public class Parent implements Serializable {
...
@OneToMany(cascade = { CascadeType.PERSIST,
CascadeType.MERGE },
mappedBy = "parent")
private Set getChildren() {
return children;
}

@Transient
public Set getUnassignedChildren() {
return unassignedChildren;
}

public void addChild(Child theChild) {
theChild.setParent(this);
children.add(theChild);
}

public void unassignChild(Child theChild) {
if (children.remove(theChild)) {
theChild.setParent(null);
unassignedChildren.add(theChild);

}
}
...
}
And Parent manager update:
public class ParentManager {
...
@Transactional(propagation = Propagation.REQUIRED,
readOnly = false)
public void updateParent(Parent parent) {
if (!parent.getUnassignedChildren().isEmpty()) {
for (Child child : parent.getUnassignedChildren()) {
childManager.update(child);
}
}
parentDAO.update(parent);
}

...
}
Thus, any change to set of children using addChild() and unassignChild() is guaranteed to propagate to the database via single update to parent entity - problem solved.