Alex Rivera | Logout

How to avoid duplicates with JPA cascades?

Asked 2011-11-27T19:50:12.243
11

I have a Parent entity with a Child entity in a ManyToOne relationship:

@Entity class Parent {
  // ...
  @ManyToOne((cascade = {CascadeType.ALL})
  private Child child;
  // ...
}

The Child has an unique field:

@Entity class Child {
  // ...
  @Column(unique = true)
  private String name;
  // ...
}

When I need a new Child, I ask the ChildDAO first:

Child child = childDao.findByName(name);
if(child == null) {
  child = new Child(name);
}

Parent parent = new Parent();
parent.setChild(child);

The problem is, if I do like above twice (with the same name for the Child), and only persist the Parent at the end, I get a constraint exception. Which seems normal, since initially there was no child in the database with the specified name.

The problem is, I'm not sure what would be the best way to avoid this situation.

Edit
Report

2 Answers

3

If you make two objects, and let JPA persist them automatically, then you'll get two rows in the database. So, you have two options: don't make two objects, or don't let JPA persist them automatically.

To avoid making two objects, you would have to arrange your code so if two Parents try to create Children with the same name, they will get the same actual instance. You would probably want a WeakHashMap (scoped to the current request, perhaps by being referred to by local variables), keyed by name, where Parents can look up their new Child's name to see if the Child already exists. If not, they can create the object and put it in the map.

To avoid having JPA persist the objects automatically, drop the cascade and use persist to manually add the objects to the context immediately after creation.

Since a persistence context is basically a tricked-out WeakHashMap attached to a database, these approaches are pretty similar when it comes down to it.

answered 2011-11-27T23:33:08.627
0

You are setting a child object then if persist the parent you are storing a register in the database that points to a non existent child.

When you create a new object it must be managed by the entityManager in the same way when you "find" an object using the DAO it must get the register from DB and put the object in the entityManager context.

Try to first persist or merge the child object.

answered 2011-11-27T20:06:36.520

Your Answer