Last week we started our search for JPA implementation patterns with the Data Access Object pattern. This week we continue with another hairy subject.
JPA offers the @OneToMany, @ManyToOne, @OneToOne, and @ManyToMany annotations to map associations between objects. While EJB 2.x offered container managed relationships to manage these associations, and especially to keep bidirectional associations in sync, JPA leaves more up to the developer.
Let's start by expanding the Order example from the previous blog with an OrderLine object. It has an id, a description, a price, and a reference to the order that contains it:
@Entity public class OrderLine { @Id @GeneratedValue private int id; private String description; private int price; @ManyToOne private Order order; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public Order getOrder() { return order; } public void setOrder(Order order) { this.order = order; } }
Using the generic DAO pattern, we quickly get ourselves a very basic OrderLineDao interface and an implementation:
public interface OrderLineDao extends Dao<Integer, OrderLine> { public List<OrderLine> findOrderLinesByOrder(Order o); } public class JpaOrderLineDao extends JpaDao<Integer, OrderLine> implements OrderLineDao { public List<OrderLine> findOrderLinesByOrder(Order o) { Query q = entityManager.createQuery("SELECT e FROM " + entityClass.getName() + " e WHERE order = :entity"); q.setParameter("entity", o); return (List<OrderLine>) q.getResultList(); } }
We can use this DAO to add a orderline to an order, or to find all the order lines for an order:
OrderLine line = new OrderLine(); line.setDescription("Java Persistence with Hibernate"); line.setPrice(5999); line.setOrder(o); orderLineDao.persist(line); Collection<OrderLine> lines = orderLineDao.findOrderLinesByOrder(o);
All this is pretty straight forward, but it gets interesting when we make this association bidirectional. Let's add an orderLines field to our Order object and include a naïve implementation of the getter/setter pair:
@OneToMany(mappedBy = "order") private Set<OrderLine> orderLines = new HashSet<OrderLine>(); public Set<OrderLine> getOrderLines() { return orderLines; } public void setOrderLines(Set<OrderLine> orderLines) { this.orderLines = orderLines; }
The mappedBy field on the @OneToMany annotation tells JPA that this is the reverse side of an association and, instead of mapping this field directly to a database column, it can look at order field of a OrderLine object to know with which Order object it goes.
So without changing the underlying database we can now retrieve the orderlines for an order like this:
Collection<OrderLine> lines = o.getOrderLines();
No more need to access the OrderLineDao.
But there is a catch! While container managed relationships (CMR) as defined by EJB 2.x made sure that adding an OrderLine object to the orderLines property of an Order also sets the order property on that OrderLine (and vice versa), JPA (being a POJO framework) performs no such magic. This is actually a good thing because it makes our domain objects usable outside of a JPA container, which means you can test them more easily and use them when they have not been persisted (yet). But it can also be confusing for people that were used to EJB 2.x CMR behaviour.
If you run the examples above in separate transactions, you will find that they run correctly. But if you run them within one transaction like the code below does, you will find that the item list while be empty:
Order o = new Order(); o.setCustomerName("Mary Jackson"); o.setDate(new Date()); OrderLine line = new OrderLine(); line.setDescription("Java Persistence with Hibernate"); line.setPrice(5999); line.setOrder(o); System.out.println("Items ordered by " + o.getCustomerName() + ": "); Collection<OrderLine> lines = o.getOrderLines(); for (OrderLine each : lines) { System.out.println(each.getId() + ": " + each.getDescription() + " at $" + each.getPrice()); }
This can be fixed by adding the following line before the first System.out.println statement:
o.getOrderLines().add(line);
It works, but it's not very pretty. It breaks the abstraction and it's brittle as it depends on the user of our domain objects to correctly invoke these setters and adders. We can fix this by moving that invocation into the definition of OrderLine.setOrder(Order):
public void setOrder(Order order) { this.order = order; order.getOrderLines().add(this); }
When can do even better by encapsulating the orderLines property of the Order object in a better manner:
public Set<OrderLine> getOrderLines() { return orderLines; } public void addOrderLine(OrderLine line) { orderLines.add(line); }
And then we can redefine OrderLine.setOrder(Order) as follows:
public void setOrder(Order order) { this.order = order; order.addOrderLine(this); }
Still with me? I hope so, but if you're not, please try it out and see for yourself.
Now another problem pops up. What if someone directly invokes the Order.addOrderLine(OrderLine) method? The OrderLine will be added to the orderLines collection, but its order property will not point to the order it belongs. Modifying Order.addOrderLine(OrderLine) like below will not work because it will cause an infinite loop with addOrderLine invoking setOrder invoking addOrderLine invoking setOrder etc.:
public void addOrderLine(OrderLine line) { orderLines.add(line); line.setOrder(this); }
This problem can be solved by introducing an Order.internalAddOrderLine(OrderLine) method that only adds the line to the collection, but does not invoke line.setOrder(this). This method will then be invoked from OrderLine.setOrder(Order) and not cause an infinite loop. Users of the Order class should invoke Order.addOrderLine(OrderLine).
Taking this idea to its logical conclusion we end up with these methods for the OrderLine class:
public Order getOrder() { return order; } public void setOrder(Order order) { if (this.order != null) { this.order.internalRemoveOrderLine(this); } this.order = order; if (order != null) { order.internalAddOrderLine(this); } }
And these methods for the Order class:
public Set<OrderLine> getOrderLines() { return Collections.unmodifiableSet(orderLines); } public void addOrderLine(OrderLine line) { line.setOrder(this); } public void removeOrderLine(OrderLine line) { line.setOrder(null); } public void internalAddOrderLine(OrderLine line) { orderLines.add(line); } public void internalRemoveOrderLine(OrderLine line) { orderLines.remove(line); }
These methods provide a POJO-based implementation of the CMR logic that was built into EJB 2.x. With the typical POJOish advantages of being easier to understand, test, and maintain.
Of course there are a number of variations on this theme:
public Set<? extends OrderLine> getOrderLines() { return Collections.unmodifiableSet(orderLines); }
But this makes it harder to mock these objects with a mocking framework such as EasyMock.
There are also some things to consider when using this pattern:
Well, that wraps it up for today. I am very interested to hear your feedback on this and to hear how you manage bidirectional associations in your JPA domain objects. And of course: see you at the next pattern!
For a list of all the JPA implementation pattern blogs, please refer to the JPA implementation patterns wrap-up.
Filed under JPA, JPA implementation patterns, Java, Performance | 22 Comments »
A more formal treatment of this kind of pattern can be found in the book “Streamlined Object Modeling” by Nicola et al. The book is beginning to show its age, but is still in my top five. It catalogs 12 core “collaboration patterns” that you will encounter when building object models like this.
Be careful when doing things like removing an Order from an OrderLine; the UML concept of composition may dictate (and should) that no OrderLine can exist without an Order. There is no way to enforce this in Java really, but you can enforce the persistent aspects of it via the use of cascade deletion.
–matthew
I use the order.addItem(orderline) approach, and haven’t felt it to be unnatural, and find setting parent on a child via setOrder somewhat unnatural, but then I don’t like having setters on my domain objects.
On the child object, I usually have a constructor that takes the parent eg:
OrderLine ol = new OrderLine(parent, (more attributes)
which i think makes for a reasonable approximation of the business domain…
Thanks for sharing!
James
Thanks for the informative approach. I have been reading up on some of this via the Hibernate in Action and didn’t fully understand when the @ManyToOne and @OneToMany should be used.
Your concise example has definitely cleared it up for me!
Cheers,
Justin N.
Chicago, IL
Maintaining the bi-directional association properly might just work as good, now wouldn’t it? Resulting in cleaner code, imho…
// OrderLine public void setOrder(Order order) { if(this.order != order) { if(this.order != null) { this.order.removeLine(this); } this.order = order; if(order != null) { order.addLine(this); } } } // Order public void addLine(OrderLine line) { if(!this.orderLines.contains(line)) { this.orderLines.add(orderLine); orderLine.setOrder(this); } }@Alex: your code would also work and certainly doesn’t look so tainted with the internalXYZ methods.
But it does depend on the fact that Order.addLine first adds the orderLine to the orderLines set and only then invokes orderLine.setOrder. If some hapless developer were to switch those two statements, you would have an infinite loop on your hands.
Close call. I guess it’s a matter of taste…
All this nice API doesn’t protect the user if you return a reference to orderLines (getOrderLine) since the user can add and remove elements directly. I tried the Collections.unmodifiableList on a OneToMany List thinking that would solve the problem. However I found a case where the List was replaced when it was first lazily loaded (since it was null when empty I created a bootstrap with new ArrayList()). Now I wonder about lazyily loading a List that a refresh might replace the list and make the backing List of the unmodifiableList stale. What is the expected behavior?
@Paul: in fact in my approach getOrderLines() does indeed return an unmodifiable set. That works in this example. And I guess that is because this example uses field access. If the example were to use property (getter/setter) access, I guess it would have the behaviour you describe.
Which brings up the nice matter of field vs. property access. I actually prefer field access because it allows me to do extra stuff in my getters and setters. Not only the things I mention in this blog, but also validation or logging, etc.
Hi Vincent,
Thanks again for the series of articles on JPA
Regarding bidirectional associations, what do you make of the logic discussed in this article:
http://notesonjava.wordpress.com/2008/11/03/managing-the-bidirectional-relationship/
It avoids having the separate internal methods.
@Niran: the strategy regarding managing bidirectional associations mentioned on http://notesonjava.wordpress.com/2008/11/03/managing-the-bidirectional-relationship/ is interesting. Nut unsurprisingly the strategy is similar, but the way it’s been implemented is different.
It does not have the “internal” methods I that are used in my approach but then again they do not guarantee against anybody invoking A.getBList().add(b) directly thereby breaking the bidirectional associations. In fact that is the reason the approach I use has the “internal” methods. When possible, these should be made package scope.
We use a similar pattern in our applications (exactly lilke the one Alex Snaps posted), but we had a bit of trouble dealing with one-to-one bi-directional associations. I can see how using internalXXX methods can achieve this, Any clue as to how this can be achieved without internalXXX methods?
@Eduardo: Yeah, stopping the recursion is harder with Alex Snaps’ variation of the pattern. The internalXXX methods might not look too prerry, but at least it is pretty easy to figure out how they work.
Anyway, I think this is how you could handle one-to-one bidirectional associations without using internalXXX methods:
public class A { ... public void setB(B newB) { if(this.b != newB) { B olbB = this.b; this.b = newB; if(olbB != null && olbB.getA() == this) { olbB.setA(null); } if(newB != null) { newB.setA(this); } } } ... }The B.setA() method would be similar. YMMV as I vaven’t tried the code myself.
@Alex: How do you remove line from order?
what’s order.removeLine() look like?
Hi Everyone!
I’m Just a newbe on this. I need to know how to persist object in a many-to-many relationship.
I have two Entitys:
Entity A:
{ ................. @ManyToMany(mappedBy = "codigousuarioCollection") private Collection<B>l codigorolCollection; }Entity B:
{ ...... @JoinTable(name = "A_B", joinColumns = {@JoinColumn(name = "CODIGOROL", referencedColumnName = "CODIGOROL")}, inverseJoinColumns = { @JoinColumn(name = "CODIGOUSUARIO", referencedColumnName = "CODIGOUSUARIO")}) @ManyToMany private Collection<A> codigousuarioCollection; }How do I persist or fill the table A_B with those object (codigorol,codigousuario)?
All help will be great!
Regards, Vivi
I’m a newbie on persistance issue and I read your nice pattern carefully (and not the next one dealing with entities removal, may be I should…) and I’m ok with the bi-directionnal add through the use of your internal methods.
Nevertheless, if you try to remove an OrderLine, the removeOrderLine method seems incomplete to me :
public void removeOrderLine(OrderLine line) { line.setOrder(null); }As the passed order is null, what the code does is only (in Order):
public void setOrder(Order order) { this.order = null; }which set the order to null and… that’s all : I can’t find the bi-directional aspect while removing the orderLine.
To me, we could reconsider the removeOrderLine method to be:
public void removeOrderLine(OrderLine line) { orderLines.remove(line); line.setOrder(null); }May be it is what you meant when you said “You can do away with the removeOrderLine and internalRemoveOrderLine methods if order lines will never be removed from an order.”, no?
Thanks again for your great blog
Hi Vincent,
I must admit that I don’t really agree with you on that pattern. I find it too complicated. What you’re trying to do is putting all the management of the association in your entities. I would rather put this process in the service facace.
For me, the pattern of a bidirectional association is simple:
“Always wire both sides of a the relationship”. That’s is.
It’s especially important when your entities are not (and must not be) deleted when they are removed from the association.
In your example, Order and OrderLine are part of a composition. When an Order is deleted, I guess all it’s orderLines must be deleted too. So I suppose that adding and removing object in the association may be managed in a simple update(Order) service method.
But in other cases, adding objects to and removing object from an association should, I think, be managed in service methods. Those methods should be the ones responsibles to wire both side of the association, which are:
- adding the object to the collection of the oneToMany side
- setting the ManyToOne side
It’s important to know that even if we do only the second operation to store the relation in the database, both operation are important (that I don’t know why yet)
Thanks again for your blog
@Fabrice: The code for setOrder in the actual pattern does more then just set the order:
public void setOrder(Order order) { if (this.order != null) { this.order.internalRemoveOrderLine(this); } this.order = order; if (order != null) { order.internalAddOrderLine(this); } }See the code in the last paragraph, “The pattern”.
As mentioned in the blog, you “can move the responsibility for managing the bidirectional association from the OrderLine.setOrder(Order) method to the Order class, basically flipping the idea around. But that would mean spreading the logic over the addOrderLine and removeOrderLine methods.”
@Stephanie: I agree with you that managing the bidirectional associations in the entities themselves is not entirely pretty. Letting the association be managed by a service (be it a DAO, a repository service or a service facade) does indeed seem prettier. But it also means that you objects can only be used properly through that service. And that means they cannot be used in unit tests by themselves.
Which gets us closer to the dreaded anemic domain model. Something that is already prone to happy quickly when you come up against the problem of how to access Spring services from domain objects. Something I actually wanted to write a blog about but still haven’t found a good solution to.
But I digress. I think having a small bit of ugly management code in the domain objects is a small price to pay for the ability to use them by themselves.
Vincent said:
“@Fabrice: The code for setOrder in the actual pattern does more then just set the order:
public void setOrder(Order order) { if (this.order != null) { this.order.internalRemoveOrderLine(this); } this.order = order; if (order != null) { order.internalAddOrderLine(this); } }”
Yes of course IF the order IS NOT null which is not the case (it is NULL) when I call the removeOrderLine method of your pattern:
public void removeOrderLine(OrderLine line) { line.setOrder(NULL); }
then
public void setOrder(Order order) { if (this.order != null) { this.order.internalRemoveOrderLine(this); } this.order = order; if (order != null) { order.internalAddOrderLine(this); } }and, with order being null, it becomes:
public void setOrder(NULL) { this.order = NULL; }And the bi-directionnailty is broken here… That is why I propose to rethink the removeOrderLine(OrderLine line) method to be:
public void removeOrderLine(OrderLine line) { orderLines.remove(line); line.setOrder(null); }Do you agree?
@Fabrice: Aha, I see where you misunderstand the pattern. The first if-statement in setOrder checks the order field (this.order) instead of the order parameter. That means that it will invoke internalRemoveOrderLine on the order the orderLine was associated with.
In other words, the call becomes like this:
public void setOrder(NULL) { this.order.internalRemoveOrderLine(this); this.order = NULL; }Which is want you want. I have used this pattern in existing code *and* tried the example above before posting it, so I am pretty sure it works.
Hmmm, maybe the pattern explains itself better when the parameter name is something like newOrder.
In this case where an order line MUST belong to exactly 1 order. It seems to me a better solution to add a createOrderLine method to the Order object and pass the order into the constructor of the line
public createLine(... various details of the line...) { final line = new OrderLine(this, ......); orderLines.add(line); }In this way the Order Line must always belong to the Order and cannot be moved. However, exposing a moveToOrder method can handle the switching if needed and ensure it always belongs to an order.
I tend to use createXXX where ownership is needed and addXXX when only a relationship is needed if we then use Alex Snaps example then we can totally ignore the persistence aspects and instead treat the whole thing as pure objects.
To take care of an Order being deleted and wanting to clean up lines, you can of course cascade removes in this association.
I forgot to mention. I do not allow anyone to call a method such as getOrderLines in most cases.
I have found that in most situations exposing the details of relationships like that is simply not needed and is an example of a violation of the Principle of Least Knowledge.
It is like reaching into someones back pocket to get some cash instead of asking them to give you some cash.
reaching in, you have to know where it is and how to open the wallet, if you ask, all that is done for you and you just get the cash you asked for.
[...] Bidirectional Associations [...]