The PathProxy pattern: Persisting complex associations

PathProxy offers an easier way to persist complex relationships without so many lookup tables

1 2 3 4 5 6 7 Page 2
Page 2 of 7

Using the PathProxy pattern

The PathProxy class adds a supportive structure to your data model, as shown in in Figure 3.

Note that I'll be using the project-->manager-->developer table to introduce the PathProxy pattern. You probably wouldn't need the PathProxy class to handle those simple relationships; you could store them in lookup tables. The point is to keep things simple enough that you can focus on the PathProxy pattern. At the end of the article, we'll briefly discuss the steps required to add a task relationship to the table. Doing so is straightforward with the PathProxy in place.

Pathing, or lateral association

Although the PathProxy class has a parent, and I've used the term hierarchical, the PathProxy pattern doesn't necessarily refer to hierarchical information. Pathing is a better word for it. For example, tracking which QA engineer was working with which developer would be a "lateral" association.

Our sample application is built with Spring, JPA/Hibernate, and JSF. I've used Maven 2 as my build utility and tested the application on Tomcat 6. Installing and running the app is very easy: just unzip it, and type "mvn clean install" at the root (you'll need to have Maven 2 installed). You can also copy the tutorial.war file into Tomcat's /webapps directory. Finally, you can use mvn eclipse:eclipse to generate the appropriate .project files for Eclipse, and then just import the projects into your IDE. Maven includes similar goals for the other IDEs.

I've used JPA annotations to describe the persistence of the domain objects. I'll quickly walk you through the annotations and the Spring-JSF application setup. Then we can move on to learning about where the PathProxy class comes in.

The applicationContext.xml file in WEB-INF refers to one of two database configuration files:

Listing 1. Database configuration files in applicationContext.xml

<!--   <import resource="oracleConfig.xml" /> -->
   <import resource="hsqlConfig.xml" />

If you want to use Oracle, you can expose the oracleConfig and comment out the HSQLDB config. The app should work out of the box without any intervention from you, although the data will only be "persisted" to RAM. If you check out the oracleConfig.xml file, you'll see its set up to use Oracle XE running on localhost. It should be pretty easy to set that up for your environment if you want to.

In both database config files, the entityManagerFactory bean has <property name="generateDdl" value="true"/>, which means that the app will check for required database structures to realize the persistence mappings. If not found, it will automatically create them. Aside from being cool, this feature is great for rapid prototyping.

We'll rely closely on the sample application to see what's going on, so be sure you have it set up properly. Assuming that's done, let's get started!

PathProxy models project, manager and developer relationships.
Figure 3. PathProxy models project, manager and developer relationships

The domain model

We know we'll need three objects: Project, Manager, and Developer.

You'll see the classes in the example are marked up with annotations to define how they are persisted to the database. Take a look at the Manager property of Project.

We're not going to use PathProxy to model the Project-->Manager relationship because it doesn't need it. We'll use a simple many-to-many mapping instead. As you'll see, you can do that and still use PathProxy to track the relationship. This would be considered a kind of de-normalization of the database, because the information regarding Project-->Manager is repeated. To be clear, what we are doing is using a normal many-to-many for the Project-->Manager relationship, and then using PathProxy to represent that relationship when necessary -- specifically, when there is a developer on a given path.

We'll use the JPA many-to-many annotation to map the Project-->Manager relationship. We won't need a class for this, but JPA will create the Project_Manager table. Just keep in mind that the Project_Manager table is the cross-reference for the Project and Manager tables, not a table holding data about your ever-cheerful project manager.

The rest of the domain model is standard fare. You'll notice that the business objects implement the ManagedObject interface. ManagedObject allows us to treat all the objects the same in one important regard: we can be assured their ID is found under the getId() method. We also use the JPA's @MappedSuperclass annotation in the Person class. This is gives us the ability to keep the common functionality in the class while persisting the data to each subclass table. (See the Resources section for a nice discussion of JPA inheritance.)

Now let's take a closer look at the PathProxy class in your IDE. It has an entityType and entityId fields, which allow it to refer to any object in the system. One thing to notice about this mapping is the cascade flag on the children. What that means is that when you remove a PathProxy instance, the JPA provider (Hibernate in our case) will automatically remove any children associated with that instance. That's very important because you don't want any dangling PathProxy instances corrupting your data.

1 2 3 4 5 6 7 Page 2
Page 2 of 7