views:

393

answers:

2

Say you have a bunch of Article objects, with a "title" property. Then there's an ARTICLE table with a TITLE column. The TITLE column has a unique constraint.

The UI shows all the articles on one page, with a text field for editing the title.

Imagine a situation where you have two articles X & Y, X having the title "1" and Y having the title "2". In the page, you rename Y to "2" and X to "1", then submit the form. With the values from the form copied directly to the hibernate objects and saved, a ConstraintViolationException will occur.

It also happens if you remove a "1" article from a collection, then add another article with the title "1" and save the collection.

So what is the best way to deal with this Hibernate quirk? I get the feeling I should rearrange the UI or something. Manually checking for these conditions before saving the hibernate objects seems a bit cumbersome.

A: 

My guess is that you're trying to update each instance at a time, thus actually colliding the unique properties.

See if the Session object is being closed or flushed between each query. In this case, you'd have to change both instances before closing/flushing.

EDIT: make sure you read the next answer I posted.

André Neves
A: 

Despite my previous answer, I confirmed that permutating unique fields of two persistent entities generates a constraint violation error even if you do it in one pass.

Therefore, I would say that the simplest way to solve this issue is by not allowing any changes that would imply a field violating a unique constraint, even if the final result would be valid. This should be fairly simple to code in the UI layer.

WHY?

It seems that at least MySQL is subject to this limitation, as I found here, and apparently there isn't a simple way to fix this without serious performance penalties.

So one would think that this issue could be easily solved programmatically. It would suck, yes, but one should probably be able to write some simple code to check if your update would permutate two existing unique fields, and do it in two steps.

It can get hairy, though. Imagine permutating 3 instances instead of two. For example, "A", "B", "C" becoming "B", "C", "A". Three steps? What next?

André Neves