JPA implementation patterns: Bidirectional assocations

Vincent Partington

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.

The setup

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 {
	public List findOrderLinesByOrder(Order o);
}

public class JpaOrderLineDao extends JpaDao implements
		OrderLineDao {

	public List findOrderLinesByOrder(Order o) {
		Query q = entityManager.createQuery("SELECT e FROM "
				+ entityClass.getName() + " e WHERE order = :entity");
		q.setParameter("entity", o);
		return (List) 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 lines = orderLineDao.findOrderLinesByOrder(o);

Mo associations, mo problems

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 orderLines = new HashSet();

	public Set getOrderLines() { return orderLines; }
	public void setOrderLines(Set 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 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 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);

Fixing and fixing...

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 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).


The pattern

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 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:

  • If Order and OrderLine are in the same package, you can give the internal... methods package scope to prevent them from being invoked by accident. (This is where C++'s friend class concept would come in handy. Then again, let's not go there. ;-) ).
  • You can do away with the removeOrderLine and internalRemoveOrderLine methods if order lines will never be removed from an order.
  • 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.
  • Instead of, or in addition to, using Collections.singletonSet to make the orderLine set read-only at run-time, you can also use generic types to make it read-only at compile-time:
    public Set 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:

  • Adding an OrderLine to an Order does not automatically persist it. You'll need to also invoke the persist method on its DAO (or the EntityManager) to do that. Or you can set the cascade property of the @OneToMany annotation on the Order.orderLines property to CascadeType.PERSIST (at least) to achieve that. More on this when we discuss the EntityManager.persist method.
  • Bidirectional associations do not play well with the EntityManager.merge method. We will discuss this when we get to the subject of detached objects.
  • When an entity that is part of a bidirectional associated is (about to be) removed, it should also be removed from the other end of the association. This will also come up when we talk about the EntityManager.remove method.
  • The pattern above only works when using field access (instead of property/method access) to let your JPA provider populate your entities. Field access is used when the @Id annotation of your entity is placed on the corresponding field as opposed of the corresponding getter. Whether to prefer field access or property/method access is a contentious issue to which I will return in a later blog.
  • And last but not least; while this pattern may be a technically sound POJO-based implementation of managed associations, you can argue why you need all those getters and setters. Why would you need to be able to use both Order.addOrderLine(OrderLine) and OrderLine.setOrder(Order) to achieve the same result? Doing away with one of these could make our code simpler. See for example James Holub's article on getters and setters. Then again, we've found that this pattern gives developers that use these domain objects the flexibility to associate them as they wish.

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.

Comments (33)

  1. Matthew - Reply

    March 17, 2009 at 6:57 pm

    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

  2. James - Reply

    March 17, 2009 at 11:56 pm

    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

  3. Justin Nauman - Reply

    March 18, 2009 at 1:56 am

    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

  4. Alex Snaps - Reply

    March 24, 2009 at 1:26 pm

    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);
      }
    }
    
  5. Vincent Partington - Reply

    March 26, 2009 at 6:13 pm

    @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...

  6. Paul Copeland - Reply

    April 8, 2009 at 6:37 am

    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?

  7. Vincent Partington - Reply

    April 9, 2009 at 9:39 am

    @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.

  8. Niran - Reply

    June 2, 2009 at 11:53 am

    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.

  9. Vincent Partington - Reply

    June 13, 2009 at 11:44 am

    @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.

  10. Eduardo - Reply

    July 24, 2009 at 7:01 pm

    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?

  11. Vincent Partington - Reply

    July 25, 2009 at 10:11 am

    @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.

  12. allan - Reply

    September 30, 2009 at 8:55 am

    @Alex: How do you remove line from order?
    what's order.removeLine() look like?

  13. Vivi - Reply

    October 6, 2009 at 7:28 pm

    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&gtl 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

  14. Fabrice Leray - Reply

    October 24, 2009 at 2:03 am

    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

  15. Stephane - Reply

    October 29, 2009 at 6:40 pm

    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

  16. Vincent Partington - Reply

    October 31, 2009 at 10:26 am

    @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."

  17. Vincent Partington - Reply

    October 31, 2009 at 10:48 am

    @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.

  18. Fabrice Leray - Reply

    November 4, 2009 at 12:20 pm

    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?

  19. Vincent Partington - Reply

    November 4, 2009 at 1:39 pm

    @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.

  20. Jason Marston - Reply

    December 15, 2009 at 9:53 pm

    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.

  21. Jason Marston - Reply

    December 15, 2009 at 9:59 pm

    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.

  22. JPA Implementation Patterns | Upthrust - Reply

    February 2, 2010 at 5:42 pm

    [...] Bidirectional Associations [...]

  23. Fabrice Leray - Reply

    February 10, 2010 at 11:52 pm

    @Vincent Partington : you're true I misunderstood this part of the pattern (read too quickly I presume :)).

    Finally, for my project, I used the mentioned pattern http://notesonjava.wordpress.com/2008/11/03/managing-the-bidirectional-relationship/ and it did it pretty well. You can even make bi-directionnal may-to-many implementation (the only difference is that you have to manage 2 lists).

    Thanks again for this nice article.

  24. Niko Will - Reply

    February 14, 2010 at 10:53 am

    @Vincent Partington: I have a question on the mentioned point:

    "Adding an OrderLine to an Order does not automatically persist it. You'll need to also invoke the persist method on its DAO (or the EntityManager) to do that. Or you can set the cascade property of the @OneToMany annotation on the Order.orderLines property to CascadeType.PERSIST (at least) to achieve that. More on this when we discuss the EntityManager.persist method."

    I have a simple car configuration tool which saves all cars of a user. My entities look like the following:

    @Entity
    public class Vehicle implements Serializable {
    ...
        @ManyToOne
        private User owner;
    
        public Vehicle(User owner) {
            this.owner = owner;
            this.owner.addVehicle(this);
        }
    
        @PreRemove
        protected void preRemove() {
            this.owner.removeVehicle(this);
        }
    ...
        public User getOwner() {
            return owner;
        }
    }
    
    @Entity
    public class User implements Serializable {
    ...
        @OneToMany(mappedBy="owner", cascade={CascadeType.PERSIST, CascadeType.REMOVE})
        private List vehicles;
    
        protected User() {
            vehicles = new ArrayList();
        }
    ...
        public List getVehicles() {
            return Collections.unmodifiableList(vehicles);
        }
    
        void addVehicle(Vehicle vehicle) {
            vehicles.add(vehicle);
        }
    
        void removeVehicle(Vehicle vehicle) {
            vehicles.remove(vehicle);
        }
    }
    

    My Unit Test looks as follows:

        @Test
        public void CreateVehicleEntity() {
            User owner = new User("vehicle_jack1","jack");
            bs.getUserFacade().create(owner);
    
            Vehicle vehicle = new Vehicle(owner);
            bs.getVehicleFacade().create(vehicle);
    
            Vehicle vehicleFromDb = f.find(vehicle.getId());
            assertTrue(vehicle.getOwner().getVehicles().contains(vehicle));
            assertTrue(vehicleFromDb.getOwner().getVehicles().contains(vehicleFromDb));
        }
    

    This test fails on the last assert statement because the relaiton from owner to vehicle is not persisted. How can I achieve that this happens. If I call the merge operation on the User entity it works, but I don't want the caller to know that he has to call this explicitly. If I put a cascade.PERSIST on the ManyToOne it doesn't work either because when persisting the vehicle the user is already persisted. This makes sense because the user might want to add another car later.

    If I get you right the User Entity is in a managed context and will be saved to database on commit or end of the transaction. Is that true? Can I execute a commit within the Unit test? And when does the commit usually occurs? It is a web application and the user entity will be loaded to set the values on the GUI. If the user adds another car and the callback arrives in the servlet, I save the new car like the code describes, will the relation be there when the next callback to the servlet arrives?

    Thanks in advanced and by the way, I love your series on JPA patterns. Greetings from Germany, Niko

  25. Vincent Partington - Reply

    February 15, 2010 at 9:03 pm

    @Niko Will: I think the problem in your test is that the invocation of vehicle.getId() returns 0. Only when the entity context is saved (which by defaults happens when you invoke EntityManager.find or commit the transaction) does the ID get a value.

    As for the other questions: the persistence context usually lives exactly as long as the transaction. When you commit the transaction, the persistence context also gets flushed. The only exception to this is that the persistence context is also flushed (but the transaction not committed) when you invoke EntityManager.find and the flush mode is set to AUTO (the default).

    Unless you find a way to revive the persistence context on a new servlet request (there are ways but I have not tried them), you will always get a new one. So then it is up to the JPA provider to make sure the relations are set up correctly.

    That is exactly what makes unit testing JPA code so hard. You need multiple transactions within one test to simulate this. Which makes testing within one transaction so you can easily roll back impossible. But that is something I discuss in my JPA implementation patterns blog on testing.

  26. Niko Will - Reply

    February 16, 2010 at 7:32 am

    @Vincent Partington: Thats not true. After I call the create methode of the netbeans automatic created facade for the vehicle, which is calling the persist method of the entitymanager, the vehicle entity has an id. Actually the unit test has more entries to check all other attributes but for readability I just post the important ones to show my problem. If I compare the size of both, the original vehicle list and the one from the db I get an assertion failure that expected but it is . If the id wasn't correct set, the test should fail on the vehicleFromDb.getOwner().

    I also tried to expose a method which gives me the entitytransaction and manually flush and commit the transaction and to retrieve the vehicleFromDb in a new one. This results in the same failure.

    If I have more time I will read on your blog about testing. If you have another approach to get around my problem, please let me know.

  27. Niko Will - Reply

    February 18, 2010 at 10:49 am

    @Vincent Partington: Mea culpa... I found the problem. In the unit tests I have to use a UserTransaction and commit it before trying to read the saved entity. Thank you very much for your help. King regards

  28. Vincent Partington - Reply

    February 19, 2010 at 3:17 pm

    @Niko Will: Glad to hear you that you were able to solve the problem. And thanks for letting me know. It should now be obvious to all readers of this blog that testing JPA code is very hard. ;-)

  29. Jan - Reply

    June 21, 2010 at 2:26 pm

    Hi, I experimented with Alex Snaps proposal Posted at: March 24, 2009 at 1:26 pm.
    There is a pitfall with condition and if(!this.orderLines.contains(line)) and newly created orderLines items wit id property set to null (autogenerated after persists).

    When using the default Netbeans implementation of equals method provided by JPA support which makes equals all instances without id. This condition prevents second instance to be added in list.

    See netbeans template for JPA with modification - under comment. Consider the TripLocalizedInfo the same as OrderLine from examples above:

       @Override
        public boolean equals(Object object) {        
            if (!(object instanceof TripLocalizedInfo)) {
                return false;
            }
            TripLocalizedInfo other = (TripLocalizedInfo) object;
            if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
                return false;
            } //else if ((this.id == null && other.id == null) ) { return (this == other); }
              // instance comparsion in case no persistence
            return true;
        }
    

    I resolved that by adding line

    else if ((this.id == null && other.id == null) ) { return (this == other); } 
    // instance comparsion in case no persistence instance are compared.
    

    Is that good practice for equal methods and JPA, or should I expect troubles when going far wiht that solution?
    Jan

  30. WhiteWoolve - Reply

    September 18, 2010 at 8:53 pm

    As far as i know equals should use business keys for comparison.
    Otherwise there's an bad design according OOD.

    CU

  31. shizuki - Reply

    September 27, 2010 at 10:47 am

    hi, i think rough approach. using metamodel api(Canonical Model Generation).
    Please teach that this is wrong.

    Parent:

    @Entity
    public class Parent implements Serializable{
      @Id
      private int id;
    
      private String name;
    
      @OneToOne(mappedBy = "parent", cascade = CascadeType.ALL)
      private Child1 child;
      
      @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
      private List children;
    }
    

    Child1:

    @Entity
    public class Child1 implements Serializable{
      @Id
      private int id;
      
      private String name;
    
      @OneToOne
      private Parent parent;
    }
    

    Child2:

    @Entity
    public class Child2 implements Serializable{
      @Id
      private int id;
      
      private String name;
    
      @ManyToOne
      private Parent parent;
    }
    

    dao(concrete-class):

    public class ParentDao extends JpaDao{
    
      @Override
      protected void resolveReverseReferences(Parent row){
        resolveReverserReference(row, Parent_.child,    Child1_.parent); // SingularAttribute
        resolveReverserReference(row, Parent_.children, Child2_.parent); // ListAttribute
      }
      
    }
    

    dao(superclass):

    public abstract class JpaDao{
      private EntityManager manager;
      
      /* overriding in subclass. */
      protected void resolveReverseReferences(E row){};
      
      protected  void resolveReverseReference(T row, SingularAttribute otoAttr, SingularAttribute mappedByAttr) {
        X x = MetamodelUtil.getAttributeValue(row, otoAttr);
        if (x != null) { MetamodelUtil.setAttributeValue(x, mappedByAttr, row); }
      }
      
      protected  void resolveReverseReference(T row, ListAttribute otmAttr, SingularAttribute mappedByAttr) {
        List x = MetamodelUtil.getAttributeValue(row, otmAttr);
        if (x != null) { MetamodelUtil.setAttributeValueAll(x, mappedByAttr, row); }
      }
      
      public void persist(E row){
        resolveReverseReferences(row);
        
        manager.persist(row);
      }
      
      public void update(E row){
        resolveReverseReferences(row);
        
        if(manager.contains(row){ manager.persist(row); }else{ manager.merge(row); }
      }
    }
    

    metamodel util:

    public class MetamodelUtil{
      private static  T get(X row, Member member, Class clazz) {
        /* get value by reflection api. */
      }
      
      private static  void set(X row, Member member, T value) {
        /* set value by reflection api. */
      }
      
      public static  T getAttributeValue(X row, SingularAttribute attr) {
        return get(row, attr.getJavaMember(), attr.getJavaType());
      }
      
      public static  List getAttributeValue(X row, ListAttribute attr) {
        return get(row, attr.getJavaMember(), attr.getJavaType());
      }
    
      public static  void setAttributeValue(X row, SingularAttribute attr, T value) {
        set(row, attr.getJavaMember(), value);
      }
      
      public static  void setAttributeValueAll(List rows, SingularAttribute attr, X value) {
        for (T row : rows) { setAttributeValue(row, attr, value); }
      }
    }
    
  32. Alberto - Reply

    April 15, 2014 at 3:35 pm

    Your pattern seems very obfuscated to me. I think the best solution to this problem is avoid using ToMany relationships as it's said here: http://java.dzone.com/articles/deterring-%E2%80%9Ctomany%E2%80%9D

    Or at least create them but don't create the getters and setters for orderLines.

Add a Comment