Posts Tagged ‘jpa’

Pizza shop 2: Totaling the JPA Order, use P6Spy to prevent stupidity

I’m digging up the original Pizza Shop project to illustrate another Hibernate gotcha (it’s probably applicable to other ORM libraries as well… admittedly, I haven’t tested it). If you didn’t read the original Pizza Shop post, you can find it here. To review, here is an ERD for the system:
Today I’d like to show how not to total up the cost of the customer order. First, we are going to add P6Spy to the project. P6Spy is an excellent “JDBC wrapper” tool that sits between your application code and your actual JDBC driver. It intercepts your application’s JDBC requests and logs the results. It’s an invaluable tool for optimizing the voodoo out of an ORM tool, and the great thing is that it’s simple to setup:

1.) Change your application’s JDBC driver from whatever it currently is (e.g., org.postgresql.Driver), to the P6Spy JDBC driver, com.p6spy.engine.spy.P6SpyDriver.
2.) Modify the spy.properties file by editing the line that starts with “realdriver=”, changing the value to your actual JDBC driver.
3.) Put spy.properties on your classpath.

That’s it! Now that we have that out of the way, let’s see just how badly we can screw up a simple method in our Model class. The method we are going to add will total up the price of an order. If you look at the ERD above, you can infer that the total cost of an order is the sum of the base price for each pizza, depending on its size, plus the price of each pizza’s individual toppings.

So for our example order, let’s say we have the following:
1 Small Pizza with Pepperoni and Mushroom
1 Medium Pizza with Sausage and Onions
1 Large Pizza with Extra Cheese

You’ll recall that we created a Model class which provides a method for retrieving a List of Pizza objects that are associated with an order ID. The temptation is to create a method which looks something like this:

public BigDecimal getOrderPriceWrong(Integer orderId) {
  BigDecimal result = new BigDecimal(0.0);
  Order order = this.getOrder(orderId);
  for (Pizza pizza : order.getPizzas()) {
    result.add(pizza.getSize().getBasePrice());
    for (Topping topping : pizza.getToppings()) {
      result.add(topping.getPrice());
    }
  }
  return result;
}

Because Hibernate does lazy-fetching, it’s not going to attempt to calculate the total cost with as few queries as possible. Instead, Hibernate’s general philosophy is to defer any queries until it knows that it absolutely needs to do them, substituting empty proxy objects for populated ones until required. Usually this is an optimization, but in this case, Hibernate will do the following queries:

1.) Query to obtain an order object.
2.) One Query for each Pizza, joined to the Size, to obtain the base price.
3.) One Query per Topping, to obtain the topping price.

In all, we get nine individual SQL queries to compute the total price of our single fictional order. The proof is in the P6Spy’s output, spy.log, truncated below:

select order0_.pizza_order_id as pizza1_2_, order0_.version ...
select pizzas0_.pizza_order_id as pizza4_2_, pizzas0_.pizza_id ...
select pizzas0_.pizza_order_id as pizza4_2_, pizzas0_.pizza_id ...
select pizzas0_.pizza_order_id as pizza4_2_, pizzas0_.pizza_id ...
select toppings0_.pizza_id as pizza1_1_, toppings0_.topping_id ...
select toppings0_.pizza_id as pizza1_1_, toppings0_.topping_id ...
select toppings0_.pizza_id as pizza1_1_, toppings0_.topping_id ...
select toppings0_.pizza_id as pizza1_1_, toppings0_.topping_id ...
select toppings0_.pizza_id as pizza1_1_, toppings0_.topping_id ...

If your application is totaling up the price of Pizza orders all day, this can really add up! An alternative approach is to use two named queries to compute the total base price, and total topping price, for an order. For example, we might add the following annotation to the Pizza class:

@NamedQueries(
{
@NamedQuery(
 name="basePrice",
 query="select SUM(p.size.basePrice) " +
       "  from Pizza p " +
       " where p.order.id = :orderId"),
@NamedQuery(
 name="toppingPrice",
 query="select SUM(topping.price) " +
       "  from Pizza p join p.toppings as topping " +
       " where p.order.id = :orderId")
})

Then, you could add the following methods to the OrderDao:

public BigDecimal nullGuard(Query query) {
  BigDecimal result = (BigDecimal)query.getSingleResult();
  return (result == null ? new BigDecimal(0) : result);
}
 
public BigDecimal getOrderPrice(Integer orderId) {
  Query query1 = getEntityManager().createNamedQuery("basePrice");
  query1.setParameter("orderId",orderId);
  Query query2 = getEntityManager().createNamedQuery("toppingPrice");
  query2.setParameter("orderId", orderId);
  return nullGuard(query1).add(nullGuard(query2));
}

…and call into the DAO from the Model class, thusly:

public BigDecimal getOrderPriceRight(Integer orderId) {
  return this.orderDao.getOrderPrice(orderId);
}

When we run the P6Spy test now, we see a meager two queries where we used to have nine:

select SUM(size1_.pizza_size_base_price) as col_0_0_ from PIZZA ...
select SUM(topping2_.topping_price) as col_0_0_ from PIZZA ...

It pays to periodically use a tool like P6Spy on your application, to look for easy wins like this one!

I’ve included a complete working eclipse project that demonstrates this… it’s actually a tweaked version of the earlier Pizza Shop project. You can get it here.

Tags: , , , ,
Posted in blog | 5 Comments »


Enumerated Types with JPA, and your Sock Drawer

One feature of JPA that didn’t exist in plain-vanilla Hibernate is support for Enumerated types. I haven’t seen a lot of examples of this in practice or on the internet, so in this post I’ll show one example of how to use JDK 5 enumerations with JPA.

For our example, we are going to create an inventory system for our sock drawer. It is comprised of only two tables. The first table, called SOCK, contains one row per sock in our drawer. The columns of the table are:

  • sock_id – an auto-incrementing identity column.
  • sock_description – a varchar column for a free-form text description of the sock.
  • sock_pattern_id – a reference to a row in the SOCK_PATTERN table.

As you may have guessed, the SOCK_PATTERN table looks like this:

  • sock_pattern_id – an integer primary key. It’s not auto-incrementing, because we will want to have control over the contents of the field.
  • sock_pattern_description – a varchar column for a free-form text description of the pattern.

We need to “prime” our SOCK_PATTERN table with the valid patterns and create a foreign key relationship between the two tables:

INSERT INTO SOCK_PATTERN (sock_pattern_id,sock_pattern_description) VALUES (0,'SOLID');
INSERT INTO SOCK_PATTERN (sock_pattern_id,sock_pattern_description) VALUES (1,'STRIPES');
INSERT INTO SOCK_PATTERN (sock_pattern_id,sock_pattern_description) VALUES (2,'POLKA_DOT');
INSERT INTO SOCK_PATTERN (sock_pattern_id,sock_pattern_description) VALUES (3,'ARGYLE');

Note that we populated sock_pattern_id starting with zero; this is important because the Enumeration below is zero-indexed.

Next, let’s create the classes:

public enum SockPattern {
 SOLID, STRIPES, POLKA_DOT, ARGYLE
}
 
@Entity @Table(name="SOCK")
public class Sock {
 @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
 @Column(name="sock_id")
 private Integer id;
 
 @Column(name="sock_description")
 private String description;
 
 @Enumerated @Column(name="sock_pattern_id")
 private SockPattern pattern;
 
 public Integer getId() { return id; }
 public void setId(Integer id) { this.id = id; }
 
 public String getDescription() { return description; }
 public void setDescription(String description) { this.description = description; }
 
 public SockPattern getPattern() { return pattern; }
 public void setPattern(SockPattern pattern) { this.pattern = pattern; }
}

Now, to use our wonderful contraption, you’d do something like the following:

public class Demo {
 private static EntityManagerFactory emf;
 static {
     Demo.emf = Persistence.createEntityManagerFactory("sockdrawer");
 }
 
 @Test
 public void socksOne() {
     Sock sock = new Sock();
     sock.setDescription("My favorite sock.");
     sock.setPattern(SockPattern.ARGYLE);
     EntityManager em = Demo.emf.createEntityManager();
     em.getTransaction().begin();
     em.persist(sock);
     em.getTransaction().commit();
     em.close();
 }
}

There are some obvious pitfalls to this approach. The object/relational mapping is very brittle; for this code to work, the IDs in the database always need to match the values that the ORM tool gets from the enumeration. Changing these values at a later date could cause some surprising results, and you can’t insert new rows without updating the Enumeration and recompiling. It does obviate the need to map the SOCK_PATTERN table, and you won’t need to worry about the details of cascading the persistent state of related Sock and SockPattern objects.

It’s just a new tool in the JPA toolbox.

(The code in this blog post was tested w/ Postgres and Toplink)

Tags: , , ,
Posted in blog | 1 Comment »


A Delicious and Simple JPA Mapping tutorial: The Pizza Shop

So, another JPA tutorial. What makes this one different? Well, for one thing, this one comes with a working, downloadable project that works with Eclipse, NetBeans, and IntelliJ IDEA 7. It’s packaged with Hibernate, Toplink, and OpenJPA. And it’s been tested with MySQL, PostgreSQL, MS SQL Server, and Sybase. In other words, it works with 36 different IDE/JPA Provider/Database combinations!

Another thing that makes this tutorial different is the subject matter: Pizza! Who doesn’t love pizza? Except lactose intolerant people. And people who can’t eat gluten. But other than them, who doesn’t love pizza? So we’re going to create a simple database model for a pizza shop’s point-of-sale system.

The Schema
Unsurprisingly, the starting point for any ORM task is usually the database schema (there are people who start with the Objects and work “backward” to the schema, but I haven’t worked with any of them yet). In our example, we have a pristine, consistent, completely normalized schema. In other words, it’s probably nothing like you’ll ever be lucky enough to see in the real world! Here’s our simple little ERD:From this ERD, we can infer the following: 1.) An order is comprised of zero or more pizzas. 2.) A pizza is associated with one size. 3.) A pizza may be associated with a string of text containing “special instructions.” 4.) A pizza may have zero or more toppings. You probably also notice that each table has a column called version. This will be used for an optimistic locking strategy.

The first question is, “Where should we start?” There’s no right answer for this, but I find that it’s easiest to start working with the entities with the fewest dependencies. For example, you can’t have an order without a pizza, and you can’t have a pizza without a size, so maybe it makes sense to start with the size. But before that, we’ll want an ID interface.

An ID Interface
First things first. You’ll notice that, in our schema, every table has an integer ID. It’s often a good idea to have all of your objects implement the same interface for accessing the ID, because it makes it easier to create Generic DAOs (more about that in a future post). For now, let’s make a really simple interface like this:

public interface IdObject {
  public void setId(Integer id);
  public Integer getId();
}

Many-to-One Unidirectional Relationships
Now that we’ve gotten that out of the way, let’s create the Size class. It’s a simple POJO littered with annotations, like this:

@Entity
@Table(name="PIZZA_SIZE")
public class Size implements IdObject {
  @Id
  @Column(name="pizza_size_id")
  private Integer id;
 
  @Column(name="pizza_size_description")
  private String description;
 
  @Column(name="pizza_size_base_price")
  private BigDecimal basePrice;
 
  @Version @Column(name="version")
  private Integer version;
 
  public Integer getId() { return id; }
  public void setId(Integer id) { this.id = id; }
 
  public String getDescription() { return description; }
  public void setDescription(String description) { this.description = description; }
 
  public BigDecimal getBasePrice() { return basePrice; }
  public void setBasePrice(BigDecimal basePrice) { this.basePrice = basePrice; }
 
  public Integer getVersion() { return version; }
  public void setVersion(Integer version) { this.version = version; }
}

Here are some notes on the annotations that were used in the above class:
@Entity
tells the JPA provider that this is a managed object.
@Table specifies the table name. The JPA provider will attempt to default the table name to a sane value based on the class name, but I like to be explicit. I’m funny that way. Perhaps it’s OCD. Or a power-trip.
@Column indicates the name of the column, and can include other attributes about the column (you’ll see a few additional attributes later on). Again, JPA can try to default this to sane values for you, but I like to be explicit.
@Version indicates that a particular column is used for indicating when a row is updated. This column can then be used in an optimistic locking scheme.

Next, let’s do the Pizza object to show how we map a Pizza to a Size.
One thing I that always tripped me up when I started out with ORM
tools was the difference between “One-to-Many” and “Many-to-One.” I never knew, if I call a relationship many-to-one in my metadata, is this object the one that there are many of, or is it the other way around? The answer is that “this” object always comes first. ManyToOne means that “there are many of this object to one of those objects.” The “Many” side is often the side that has the foreign key.

In our case, there will be many Pizzas that are the same size. So when we make our Pizza object, we will want to use the @ManyToOne annotation. Here’s what the Pizza object looks like so far. I’ve omitted the getters and setters to save space:

@Entity
@Table(name="PIZZA")
public class Pizza implements IdObject {
  @Id
  @Column(name="pizza_id")
  private Integer id;
 
  @ManyToOne(cascade={CascadeType.ALL})
  @JoinColumn(name="pizza_size_id",nullable=false)
  private Size size;
 
  @Version @Column(name="version")
  private Integer version;
 
  // (Accessor methods omitted)
}

Note that, when we made our Size object, we did not include a reference to the Pizza. That was an intentional design decision. In this application, it’s unlikely that we will want to instantiate a Size object, and get a collection containing all of the Pizzas of that size, so we don’t bother with mapping it. This is called unidirectional association.

The @ManyToOne annotation specifies a cascade attribute. There are several different settings for this attribute, which you can read more about here. I tend to cascade the persistent state to all related objects because it reduces the amount of redundant API calls. By default, JPA does not cascade pers istence to related objects. I’ll cover the cascade attribute in future posts, but for now, we’ll go with my personal preference, because I’m writing the article!

The @JoinColumn annotation indicates the column name that defines the linkage between the Pizza and the Size. You’ll also note that we’ve included some additional attributes on our @Column and @JoinColumn annotations. The unique and nullable attributes are particularly useful if you use tools to generate schema DDL from your mappings.

One-to-Many bidirectional relationships
Both the SpecialInstruction and the Order objects are examples of One-to-Many bidirectional relationships. In the case of SpecialInstruction, it is likely that we will care about which Pizza an instruction is associated with, and likewise for the Order. A bidirectional one-to-many relationship implies that one object has a collection of other o bjects. For example, an Order has a collection of Pizzas. First, lets add an order attribute to our Pizza object:

@Entity
@Table(name="PIZZA")
public class Pizza implements IdObject {
.
.
  @ManyToOne(cascade={CascadeType.ALL})
  @JoinColumn(name="pizza_order_id",nullable=false)
  private Order order;
 
  public Order getOrder() { return order; }
  public void setOrder(Order order) { this.order = order; }
.
.
}

Next, let’s create an Order object to contain our collection of Pizzas, like this:

@Entity
@Table(name="PIZZA_ORDER")
public class Order implements IdObject {
  @Id
  @Column(name="pizza_order_id")
  private Integer id;
 
  @OneToMany(cascade={CascadeType.ALL},mappedBy="order")
  private Set pizzas = new HashSet();
 
  @Version @Column(name="version")
  private Integer version;
 
  // (version and id accessors omitted)
 
  public Set getPizzas() {  return pizzas; }
  public void setPizzas(Set pizzas) { this.pizzas = pizzas; }
  public void addPizza(Pizza pizza) {  pizza.setOrder(this);  this.pizzas.add(pizza); }
}

There are a couple of things you worth noting about this mapping:
1.) The @OneToMany annotation uses the mappedBy attribute to indicate which member of the related object defines the linkage between the two tables. In this case, we are saying that the Pizza object contains a member named order, which defines the linkage between the two objects.
2.) I’ve created a utility method called addPizza. This simplifies setting both sides of the bidirectional relationship by setting the Order object on the Pizza and adding the Pizza to the Order’s collection. Users of this class will only need to make one method call to do both.

Many-to-Many relationships via a Join Table
The last thing we’ll cover is how to map Join Tables. In our ERD, you can see that Toppings are modeled in the database with a TOPPING table that contains all of the valid toppings, a PIZZA table that contains all of the valid Pizzas, and a PIZZA_TOPPING table in the middle that maps all of the valid Pizzas to all of the valid Toppings. You could create an object called PizzaTopping that corresponds to the PIZZA_TOPPING table. Then you could have a One-to-Many relationship from the Pizza to the PizzaTopping, and a One-to-One from each PizzaTopping to a Topping. That would be very cumbersome to work with! Fortunately, there’s a better way.

Logically, a Pizza has a collection of Toppings. In our Java code, we really shouldn’t care about the fact that there is a PIZZA_TOPPING join table in the middle. First, let’s create a simple Topping class:

@Entity
@Table(name="TOPPING")
public class Topping implements IdObject {
  @Id
  @Column(name="topping_id")
  private Integer id;
 
  @Column(name="topping_description")
  private String description;
 
  @Column(name="topping_price")
  private BigDecimal price;
 
  @Version @Column(name="version")
  private Integer version;
 
  // (Accessors omitted)
}

This is how the association would be mapped in the Pizza class:

@Entity
@Table(name="PIZZA")
public class Pizza implements IdObject {
.
.
  @ManyToMany(cascade={CascadeType.ALL})
  @JoinTable(name="PIZZA_TOPPING",
             joinColumns=@JoinColumn(name="pizza_id"),
             inverseJoinColumns=@JoinColumn(name="topping_id"))
  private Set toppings = new HashSet();
 
  public Set getToppings() { return toppings; }
  public void setToppings(Set toppings) { this.toppings = toppings; }
  public void addTopping(Topping topping) { this.toppings.add(topping); }
.
.
}

The @JoinTable annotation defines three key attributes:
name: Identifies the name of the join table.
joinColumns: This attribute identifies the column name in the join table that points to this object.
inverseJoinColumns: This attribute defines the column name in the join table that points to the other objects.

From your Java code, the semantics for dealing with toppings on a pizza are just like any other set, much like you’d work with a One-to-many object.

Conclusion
Since the introduction of annotations, object/relational mapping is one of the easiest aspects of working with JPA over other frameworks. You can see this whole project in action on your IDE of choice by downloading it here (or from here if that doesn’t work for some reason). It should be a pretty reasonable starting point if you want a reference project to start playing with JPA. I hope to revisit the Pizza Shop project to cover other JPA topics in future posts.

Tags: , , , ,
Posted in blog | 8 Comments »