Hibernate NonUniqueObjectException

T

Tobias Köhler

Hallo,

ich habe ein Problem beim Insert bestimmter Daten. Ich beschreib dann mal;) :

Es gibt eine Charge, diese könnte schon in der DB sein oder nicht- mein Code dazu:

Java:
//----- Charge -----
			Charge c = new Charge();
			c.setName(d.getCharge());
			
			Query queryCharge = session.createQuery(
			"select c from Charge c where c.name = ?");
			queryCharge.setString(0, c.getName());
			List objectCharge = queryCharge.list();

			boolean chargeInTable = false;
			if(objectCharge.size()!=0)
			{
				for(int i=0; i<objectCharge.size(); i++)
				{
					Charge obj = (Charge) objectCharge.get(i);
					if(obj.getName().equals(c.getName()))
					{
						chargeInTable = true;
						c.setId(obj.getId());
						break;
					}	
				}									
			}
			if(!chargeInTable)
				session.save(c);
			else
			{
				Charge holder = (Charge)session.load(Charge.class, c.getId());
				holder = c;
			}

Als Nächstes gibt es hierzu einen Eintrag, der evtl auch schon in der DB sein könnte:
Java:
QM q = new QM();
			q.setCharge(c);
			q.setIga(d.getIga());
			q.setIgg(d.getIgg());
			q.setIgm(d.getIgm());
			q.setBemerkungen(d.getBemerkungen());

			Query queryQM = session.createQuery(
					"select q from QM q");
			List objects = queryQM.list();

			boolean qmInTable = false;
			if(objects.size()!=0)
			{
				for(int i=0; i<objects.size(); i++)
				{
					QM holder = (QM) objects.get(i);
					if(holder.getId()==q.getId())
					{
						qmInTable = true;
						q.setId(holder.getId());
						break;
					}
				}
			}
			if(!qmInTable)
				session.save(q);
			else
			{
				QM holder = (QM)session.load(QM.class, q.getId());
				holder = q;
			}

So, und führe ich das aus, kommt dieser Fehler:
Java:
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [de.lagerverwaltung.entities.QM#5548]
	

//und zwar andieser Stelle
if(!qmInTable)
				session.save(q);

Was kann ich tun, damit das nicht mehr passiert?
 
Zuletzt bearbeitet von einem Moderator:
Logisch, du hast an der stelle schon ein Objekt holder, dass diese Id hat. Wenn du nun ein anderes mit der gleichen Id speicherst, sind plötzlich zwei Objekte mit der gleichen Id da. Das geht in keiner Datenbank.

Diese komplexe Abgfrage mit der SChleife danach macht für mich eh keinen Sinn. Du liest alle QM objekte aus um danach händisch drüber zu iterieren und bei einer bestimmten Id das Objekt zu holen. Für sowas gibt es load/get auf der Session. Load wirft ne Exception, wenn kein Objekt mit der Id vohanden ist, get gibt einfach null zurück.

Gruß
Ollie
 
Die Schleife ist dazu da, um herauszufinden, ob das Objekt bereits in der DB ist und wenn ja, dann soll dieses geupdatet werden. Da ich die ID vorher nicht weiß, war das die einzige Möglichkeit, die mir eingefallen ist.
 
Hallo,

könntest du mir mal bitte das erklären?

Code:
if(holder.getId()==q.getId())
{
                        qmInTable = true;
                        q.setId(holder.getId());

Wenn die ID noch nicht drin steht, wie vergleichst du dann?

Im Normalfall wird ein Object aus der DB gelesen, dann geupdatet und dann wieder gespeichert.

Erklär mir bitte auch mal das
Code:
if(obj.getName().equals(c.getName()))                    
{
                        chargeInTable = true;
                        c.setId(obj.getId());
                        break;                    
}

Wenn du mehrere mit dem gleichen Namen hast, setzt du alle auf die gleiche ID. Das kann nicht funktionieren.

MFG

Sascha
 
Zum ersten Schnipsel:
leuchtet ein, allerdings weiß ich nicht wie ich das sonst machecn könnte.... Könnte ich den Vergleich sonst über ein anderes Feld ziehen, das ebenfalls eindeutig ist? Zb
if(holder.getBemerkung().equals(q.getBemerkung() )
?

Zum zweiten:
"Wenn du mehrere mit dem gleichen Namen hast, setzt du alle auf die gleiche ID."
- Es geht mir nicht darum, ob da mehrere drin sind, sondern vielmehr ob da überhaupt eins drin ist. 1. Weiß ich, dass es nur jeweils einen Eintrag mit der ID(Jede Zeile ist anders) und 2. dient das gleichzeitig dem herausfinden der ID, da ich keine andere möglichkeit wüsste. Und 3. weiße ich das nicht mehreren zu, daher ja das break, damit er nicht weiter sucht;)
 
Ich kenne dein Programm leider nicht. Deshalb kann ich noch nicht sagen, wie du es anders machen könntest. Wie ich vorhin schon gesagt hab, lädt man eigentlich erstmal das Object aus der Datenbank. Dann wird es verändern(update) und dann wieder abgespeichert.

Das einzige was Eindeutig ist, ist die ID. Bei allem anderen kannst du nicht davon ausgehen, dass es eindeutig ist. Wenn du es auf diese Weise löst, z.b. mit der Bemerkung, dann wirst du früher oder später Probleme haben, dass das falsche Object geupdatet wird.

Du musst vor der Bearbeitung sicher sein, welches Object geupdatet werden soll.

Ich schätze, dass die Objecte über eine Eingabemaske bearbeitet werden, oder? Wie wird denn bestimmt was bearbeitet wird?

MFG

Sascha
 
Bis auf 2 Felder werden alle anderen Daten eingegeben. Die anderen beiden werden berechnet. Und sobald die Zeile fertig ist, wird diese auf die verschiedenen Tabellen aufgeteilt. Es kann aber auch sein, dass eine Zeile ein update erhalten soll. Und da eine Zeile über die verschiedenen Tabellen aufgespalten ist, ensteht das HickHack mit der ID.
 
Im übrigen geht dein Code doch davon aus, dass du eine ID in q hast. Wie soll der sonst g.getId() mit irgendwas vergleichen? Dann kannst also auch gleich session.get(QM.class, q.getId()) machen.

Ich vermute sowas wie ein DAO wäre auch was sinnvolles. Schon in deinem kurzen Schnipsel stecken sachen, die Geschäftslogik sind und Sachen die Datenzugriffslogik sind.

Gruß
Ollie
 
So, mal schauen ob ich es richtig verstanden hab.

Du hast eine Tabelle. Dort werden die Daten eingegeben. Es kann sein, dass eine neue Zeile hinzugefügt wird und dort Daten eingegeben werden. Es ist aber auch möglich, dass eine vorhandene Zeile editiert wird. Sehe ich das richtig?

MFG

Sascha
 

Neue Beiträge

Zurück