We provide a variety of services including:

·          Training classes for Spring, Hibernate and Acegi Security

·          Jumpstarts to get your project off to the right start

·          Reviews to improve your architecture, code and development process

For more information visit our website: http://www.chrisrichardson.net

 

Home > Knowledge > Design > Repositories 101

 

Repositories 101

Chris Richardson, chris@chrisrichardson.net

The Repository pattern is one of the patterns described in the excellent book Domain-Driven Design by Eric Evans. A repository is a class that provides the illusion of an in-memory collection of objects and has methods for adding and removing objects and finding objects that match some criteria. The collection of objects managed by a repository almost always resides in the database. As simple as the idea sounds, it’s one of the most frequently discussed topics on the domain-driven design mailing list. In this brief article, I describe how I implement repositories.

The interface

One of the central domain classes in the Project Track application is the Project. The domain model defines a ProjectRepository class, which provides access to projects. Here is the interface:

 

public interface ProjectRepository {

  public void add(Project project);

  public Project get(int id);

  public Project merge(Project project);

  public List getAllProjects(ProjectColumnType sortColumn);

  public List getProjectsWaitingApprovalByRole(RoleType role,

                         ProjectColumnType sortColumn);

}

 

The purpose of each method is as follows:

·        add() - persists a newly created project

·        get() – retrieves a project by it’s id

·        merge() – reattaches object by merging

·        getAllProjects() – retrieves all projects sorted in the specified way

·        getProjectsWaitingApprovalByRole() – returns all projects that are waiting approval by someone of particular role

The implementation

The implementation has a single implementation class, which uses the Spring/Hibernate APIs to access the database.

public class HibernateProjectRepository

      extends HibernateDaoSupport implements ProjectRepository {

 

  public void add(Project project) {

    getHibernateTemplate().save(project);

  }

 

  public Project get(int id)  {

    Project project = (Project)

               getHibernateTemplate().get(Project.class,id);

    return project;

  }

 

  public Project merge(Project project) {

    return (Project) getHibernateTemplate().merge(project);

  }

 

  public List getAllProjects(ProjectColumnType sortColumn) {

    String queryString = "from Project as p order by p." +

               computeSortOrder(sortColumn);

    List projects = getHibernateTemplate().find(queryString);

    return projects;

  }

 

  protected String computeSortOrder(ProjectColumnType sortColumn) {

    if (sortColumn == null ||

                ProjectColumnType.NAME.equals(sortColumn))

      return "name";

    if (ProjectColumnType.ROLE.equals(sortColumn))

      return "status.role";

    if (ProjectColumnType.STATUS.equals(sortColumn))

      return "status.name";

    if (ProjectColumnType.TYPE.equals(sortColumn))

      return "type";

    throw new UnsupportedOperationException("Unsupported sort order: "

        + sortColumn);

  }

 

  public List getProjectsWaitingApprovalByRole(final RoleType role,

      final ProjectColumnType sortColumn) {

    return getHibernateTemplate().executeFind(new HibernateCallback() {

 

      public Object doInHibernate(Session session) {

        Criteria criteria = session.createCriteria(Project.class);

        criteria.createAlias("status", "status");

        criteria.add(Restrictions.eq("status.role", role));

        criteria.addOrder(Order.asc(computeSortOrder(sortColumn)));

        return criteria.list();

      }

    });

  }

 

}

This class is in a different package to the interface and in some cases in an entirely separate project.

Testing

For testing, I don’t bother with an in-memory implementation of the repository interface. I long ago decided that it was too much work. Instead, some tests use mock objects (http://projecttrack.googlecode.com/svn/trunk/services/src/test/java/org/jia/ptrack/services/ProjectCoordinatorImplMockTests.java) and others use HSQLDB, an in-memory database, with a schema that Hibernate automatically generates from the mapping file.

That’s pretty much all there is to it.