|
Re: Mysterious duplicate insert [message #781763 is a reply to message #781572] |
Sun, 22 January 2012 07:14 |
Tom Eugelink Messages: 825 Registered: July 2009 |
Senior Member |
|
|
I recently also had a truck load of unexpected (automagic) behavior that made life difficult, so I stripped away all cascading. I now have to call persist on each entity explicitly (not such a big problem, these actions are often well know) and added a delayed merge call (something I added on my own) in my property change events on all entities: whenever an object changes, and it is already persisted, it should be stored to the db.
Seems to work like a charm (still fishing out some missing persist calls here and there, but overall it's a go.) So advice: get rid of the cascade and try again.
Tom
On 2012-01-21 18:31, Christoph L wrote:
> Hello,
>
> the following code produces a wrong duplicate insert of the User entity which triggers an sql constraint error.
>
> I've tried with 2.3.3 nightly and 2.4.0 nightly but they have the same behavior. The DB doesn't matter.
>
> The testcase assumes an empty DB.
>
> Am I doing something wrong?
>
>
> Thanks
>
>
>
>
> package test;
>
> import java.util.HashMap;
>
> import javax.persistence.CascadeType;
> import javax.persistence.Entity;
> import javax.persistence.EntityManager;
> import javax.persistence.EntityManagerFactory;
> import javax.persistence.EntityTransaction;
> import javax.persistence.GeneratedValue;
> import javax.persistence.Id;
> import javax.persistence.ManyToOne;
> import javax.persistence.MappedSuperclass;
> import javax.persistence.NoResultException;
> import javax.persistence.Persistence;
> import javax.persistence.Query;
> import javax.persistence.Table;
>
> public class Main {
>
> protected static EntityManager em;
> protected static EntityManager em2;
>
> public static void main(String[] args) {
> EntityManagerFactory emf = Persistence.createEntityManagerFactory("test", new HashMap<Object, Object>());
> em = emf.createEntityManager();
> em2 = emf.createEntityManager();
>
> User alice = new User("alice");
> Foo foo = new Foo();
> Bar bar = new Bar();
> foo.bar = bar;
>
> create(alice);
> create(foo);
> create(bar);
> }
>
> public static User getUser() {
> Query q = em2.createQuery("select x from User x where x.name='alice'");
> try {
> return (User) q.getSingleResult();
> } catch (NoResultException e) {
> return null;
> }
> }
>
> public static void create(BaseEntity entity) {
> entity.createdBy = getUser();
> EntityTransaction tx = em.getTransaction();
> tx.begin();
> em.persist(entity);
> tx.commit();
> }
> }
>
> @MappedSuperclass
> abstract class BaseEntity {
> @Id
> @GeneratedValue
> Long id;
>
> @ManyToOne
> User createdBy;
> }
>
> @Entity
> @Table(name = "user2")
> class User extends BaseEntity {
>
> String name;
>
> public User() {
> }
>
> public User(String name) {
> this.name = name;
> }
> }
>
> @Entity
> class Foo extends BaseEntity {
> @ManyToOne(cascade = CascadeType.PERSIST)
> Bar bar;
> }
>
> @Entity
> class Bar extends BaseEntity {
>
> }
>
>
>
> <persistence ...>
> <persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
>
> <class>test.BaseEntity</class>
> <class>test.User</class>
> <class>test.Foo</class>
> <class>test.Bar</class>
>
> <properties>
> <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
> <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost/testdb" />
> <property name="javax.persistence.jdbc.user" value="postgres" />
> <property name="javax.persistence.jdbc.password" value="postgres" />
> <property name="eclipselink.weaving" value="false" />
> <property name="eclipselink.ddl-generation" value="create-tables" />
> <property name="eclipselink.target-database" value="PostgreSQL" />
> <property name="eclipselink.logging.level" value="ALL" />
> </properties>
> </persistence-unit>
>
> </persistence>
>
>
|
|
|
Re: Mysterious duplicate insert [message #782349 is a reply to message #781763] |
Mon, 23 January 2012 15:29 |
|
You are using two different persistence contexts and objects from each and associating them to each-other.
i.e. your user is from em2 and you assign it to the foo that you persist to em, but never merge or find this object.
you need to find the user from em not em2, or merge it and used the merged instance of em.
Also you are persisting bar twice, once from Foo and once on its own in a new transaction, which is invalid, as you cannot call persist on a non managed existing object, only new objects.
There is a persistence unit property, "eclipselink.validate-existence"="true", which will not make this work, but will throw a validation error when you attempt to do this, instead of a constraint error.
James : Wiki : Book : Blog : Twitter
|
|
|
Re: Mysterious duplicate insert [message #782351 is a reply to message #781763] |
Mon, 23 January 2012 15:29 |
|
You are using two different persistence contexts and objects from each and associating them to each-other.
i.e. your user is from em2 and you assign it to the foo that you persist to em, but never merge or find this object.
you need to find the user from em not em2, or merge it and used the merged instance of em.
Also you are persisting bar twice, once from Foo and once on its own in a new transaction, which is invalid, as you cannot call persist on a non managed existing object, only new objects.
There is a persistence unit property, "eclipselink.validate-existence"="true", which will not make this work, but will throw a validation error when you attempt to do this, instead of a constraint error.
--
James : http://wiki.eclipse.org/EclipseLink : http://en.wikibooks.org/wiki/Java_Persistence : http://java-persistence-performance.blogspot.com/
James : Wiki : Book : Blog : Twitter
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.03281 seconds