3

My class Foo has method:

 protected void saveMany(Collection<T> many) {  
    for(Object one : many) {
            one = session.merge(one); // also tried this commented out
            session.saveOrUpdate(one); // session.merge(one);   
        }

Tried to use saveOrUpdate and also merge, but both gave me this exception:

Error: Invocation of method 'saveMany' in class Foo threw exception class org.hibernate.HibernateException : org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [Bar#581301]

How to fix this?

Side note:

When I truncate my table, the saving part works, but when I have the table populated, and run this method again, thus updating the table, it fails, with this exception

Jaanus
  • 16,161
  • 49
  • 147
  • 202
  • When you called `merge()` did you remember to call `saveOrUpdate()` afterwards on the instance *returned* from merge() and not the instance you passed into merge() as a parameter? See [my answer here](http://stackoverflow.com/questions/11903653/in-a-transactional-function-calling-clear-detach-all-entities/11904050#11904050) – Brad Aug 13 '12 at 13:24
  • @Brad : no I didnt call saveOrUpdate at all, I just called merge. You mean something like this? `session.saveOrUpdate(session.merge(one))`, it says : `The left-hand side of an assignment must be a variable` – Jaanus Aug 13 '12 at 13:33
  • @Brad : I did this : `one = session.merge(one); session.saveOrUpdate(one);` – Jaanus Aug 13 '12 at 13:39
  • http://stackoverflow.com/questions/1074081/hibernate-error-org-hibernate-nonuniqueobjectexception-a-different-object-with – invariant Aug 13 '12 at 13:48
  • @invariant Okay I think I found where this happens, but how can I get the first instance of the object out of hibernate context? – Jaanus Aug 13 '12 at 14:02
  • what is the annotation on your primary key field ? – invariant Aug 13 '12 at 14:07
  • @invariant : `@Id @Column(name = "id")` – Jaanus Aug 13 '12 at 14:15
  • can you try hibernate hilo generator on your primary column ? – invariant Aug 13 '12 at 14:32
  • @Brad : yeap I didnt call merge + saveOrUpdate, so post it as answer. – Jaanus Aug 13 '12 at 14:40
  • Jaanus, I added my answer but your question looks like it has merge() followed by saveOrUpdate() now – Brad Aug 13 '12 at 14:54

4 Answers4

6

If you have a detached instance of a Class with @Id that already exists in the Hibernate Session cache, then you will have to call merge() to merge the detached instance into the cache. Then you should call saveOrUpdate().

But you have to be careful to persist the instance returned from the call to merge() and not the instance you passed in as a parameter. So you code has to look like this

mergedOne = session.merge(one);
session.saveOrUpdate(mergedOne);

If you're operating inside a transaction the database will not be updated until the session ends and the transaction commits, or you explicitly call flush()

Brad
  • 15,186
  • 11
  • 60
  • 74
1

It says that you are trying to save a new object with an Id already used by another one.

Probably, you do not have properly implemented equals and hashCode. So, hibernate finds that you want to save Object2 with id1, and in the database there is Object2 with id1, but not Object2.equals(Object1)

SJuan76
  • 24,532
  • 6
  • 47
  • 87
  • Maybe, but thats what I want to do: When there is object with same primary key in database, just overwrite the fields. – Jaanus Aug 13 '12 at 13:44
  • But does your object implement equals()? Even if it is just an equals of the id. In a course about JPA (ok, not Hibernate) I was told that you must properly implement equals for it to work. – SJuan76 Aug 13 '12 at 16:00
  • No it doesnt, can you give me a link about what you mean? I don't have equals nowhere. – Jaanus Aug 13 '12 at 16:02
  • https://community.jboss.org/wiki/EqualsandHashCode; http://stackoverflow.com/questions/5031614/the-jpa-hashcode-equals-dilemma; http://stackoverflow.com/questions/4388360/should-i-write-equals-methods-in-jpa-entities – SJuan76 Aug 13 '12 at 17:03
  • Wow, this is really confusing and I don't really understand, why I must make another identifier, when I got primary key. – Jaanus Aug 13 '12 at 19:28
  • It is when your entity has a natural/bussiness key (say, SSN) but your id is generated. Two objects with the same SSN represent the same person, the implementation of equals() and hashCode() tells that to Hibernate so it can avoid inserting the same person twice. – SJuan76 Aug 13 '12 at 19:38
  • Is it also viable when my primary key is not autogenerated? – Jaanus Aug 13 '12 at 19:43
  • Then it should be implemented, too. The difference is that when using directly the natural key, then the Entities always have its id when inserting/updating and then the problem of duplicates won't happen, but it is still good practice. – SJuan76 Aug 13 '12 at 19:44
  • Are you familiar with hibernate merge? since it resolved my problem this time. – Jaanus Aug 13 '12 at 19:44
0

You have multiple versions of "one" in the cache of your Hibernatesessions!

You must must find the instances of "one" and remove the cache-information from the Hibernatesessions using ".evict(...)".

Finally you can call saveOrUpdate succesuflly!

Grim
  • 1,938
  • 10
  • 56
  • 123
  • I think I am doing this, but I close my last session. – Jaanus Aug 13 '12 at 14:03
  • close != evict. The reference between the "one" and the closed-session is still given! What sais the System.out.println(one.getClass()) ? – Grim Aug 13 '12 at 14:31
0

You are probably trying to Save List<T> which has one or more equals objects.

Use SaveOrUpdate or merge to solve it or simpply try to make all objects unique.

danny.lesnik
  • 18,479
  • 29
  • 135
  • 200
  • No I don't have List, I have object `T`. I tried using merge and saveOrUpdate as seen in initial post. – Jaanus Aug 13 '12 at 13:41
  • You are passing Collection and List extends Collection so your Collection has duplicates. Try to remove those duplicates. – danny.lesnik Aug 13 '12 at 13:44
  • Could it be the problem that my actual method has 2 collections for arguments like this : `saveMany(Collection update, Collection delete)` . I removed one from initial code to simplify things. – Jaanus Aug 13 '12 at 13:46