Adding a child twice to the parent throwing a NonUniqueObjectException

Say I have a screen showing animals on my farm. If the user wants to add animals, they can click the "add" button, which will lead you to another screen that lists the names of animals. If the user selects β€œdog”, my application will query the database and return the β€œDog” object to me, and I will add it to my collection of animals in my farm.

In the above situation, if I were to save the Farm object, the farm would be successfully saved as expected.

However, if the user adds the β€œdog” to the farm, and then decides to add the β€œdog” again, saving the Farm object results in:

org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session

Now this makes sense because the user has selected the β€œdog” twice, causing my application to dig up two instances of the β€œdog”. What is the best way to handle this situation?

Edit: Let me clarify that animals are not directly attached to the Farm. The farm will contain an AnimalShelters collection in which anyone can place an animal. AnimalShelters are unique and have their own identifiers. I suppose you could think of a β€œdog” as a privileged dog that could boast between several shelters.

Edit: This is how the work works:

  • The first screen shows the farm. No AnimalShelters.
  • User clicks the add button to add AnimalShelter
  • ,
  • , , "find" [ ]
  • AnimalShelter
  • ​​ AnimalShelter
  • "" AnimalShelter, ( 5 )

: , , :

  • animal1 = session.get(Animal.class, 1L);
  • Commit Transaction
  • 1 AnimalShelter,
  • animal2 = session.get(Animal.class, 1L); // Animal Animal 3, , . Animal, ?
  • Commit Transaction
  • 2 AnimalShelter, Farm // , Animal

: :

+---------------+
| Farm          |
+---------------+
| Id (pk)       |
| Name          |
+---------------+

+---------------+
| AnimalShelter |
+---------------+
| Id (pk)       |
| AnimalId      |
| FarmId        |
+---------------+

+---------------+
| Animal        |
+---------------+
| Id (pk)       |
| Name          |
+---------------+

: Stacktrace:

org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.spike.model.Animal#1]
at org.hibernate.engine.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:637)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:305)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:246)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:112)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:677)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:669)
at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:252)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:392)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:335)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
at org.hibernate.engine.Cascade.cascade(Cascade.java:161)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:451)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:144)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:117)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:677)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:669)
at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:252)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:392)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:335)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:425)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:362)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:338)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
at org.hibernate.engine.Cascade.cascade(Cascade.java:161)
at org.hibernate.engine.Cascade.cascade(Cascade.java:127)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.cascadeOnUpdate(DefaultSaveOrUpdateEventListener.java:376)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:350)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:246)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:112)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:677)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:669)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:665)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:344)
at $Proxy14.saveOrUpdate(Unknown Source)
at com.spike.ui.SaveFarmActionListener.actionPerformed(SaveFarmActionListener.java:29)

: , , , :

  • animal1 = session.get(Animal.class, 1L);
  • 1 AnimalShelter,
  • animal2 = session.get(Animal.class, 1L); // Animal,
  • 2 AnimalShelter, Farm // , Animal
  • Commit Transaction - , , , Animal

: , , , , , Animal. , , , - , , . AnimalShelter, Dog, , , , , .

+3
3

, AnimalShelter. " " Animal AnimalShelter.

equals() .

public boolean equals(Object that) {
    if ( this == that ) return true;
    if ( !(that instanceof Dog) ) return false;
    Dog dog = (Dog)that;
    // Assuming id is of Long type
    return this.id.longValue() == dog.id.longValue();
}

hashcode().

+1

:

org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session

, , EntityManager (, , Dog?), . .

Dog ( em.persist() ), , . , SQL INSERT . , . ? , , .

Dog, , "", "". , em.merge() , ( ) merge(). , , , , , "".

, :

"" - "" , AnimalShelter ?

find EntityManager find() :

em.find(Dog.class, myDogPrimaryKeyValue)

Dog, "" EntityManager. EntityManager Dog , find() . , , EntityManager EntityManager. EntityManager, , EntityManager. . , merge(), , (A.K.A. "" ). , EntityManager, em.contains() .

EDIT:

, , -, . , , ? , . EntityManager, .

+1

- . , , :

  • , , AnimalShelter, AnimalShelter , SINGLE. , Animal ;
  • equals()/hashCode() Animal
  • merge()
  • session.evict(...) , , .
  • , , , . ALL, . ALL , . ALL. ( ) , !
+1

Source: https://habr.com/ru/post/1775781/


All Articles