JPA Generische Methoden

fsicher

Bekanntes Mitglied
Hallo allerseits

Ich möchte eine generische Methode implementieren, die das Löschen der übergebenen Entity realisieren soll. Nachfolgend mein Code:

Java:
public <T> void delete(T object) throws Exception {

		int id = 0;

		Class<? extends Object> c = object.getClass();

		Method m = c.getMethod("getId", new Class<?>[0]);
		Integer value = (Integer) m.invoke(object, new Object[0]);
		id = value.intValue();

		final EntityManager em = Util.getEntityManagerFactory()
				.createEntityManager();
		boolean success = false;

		try {
			em.getTransaction().begin();

			@SuppressWarnings("unchecked")
			T temp = (T) em.find(c, id);

			if (temp != null) {
				em.remove(temp);
				success = true;
			}

		} catch (Exception e) {
			logger.error(
					"Fehler beim Löschen des Objekts [" + object.toString()
							+ "]" + ": ", e);
			throw e;

		} finally {
			if (success) {
				em.getTransaction().commit();
			} else {
				em.getTransaction().rollback();
			}

			if (em != null && em.isOpen()) {
				em.close();
			}
		}
	}

Was mich stört ist die Annotation:

Java:
@SuppressWarnings("unchecked")

Ich weiss schon, dass dies nicht "lebenswichtig" ist: es handelt sich um eine "unsichere" Typumwandlung (Zeile 19). Aber trotzdem: Könnte man den Code so ändern (anpassen etc.), dass diese Annotation nicht mehr benötigt wird bzw. dass diese "unsichere" Typumwandlung eliminiert wird? Im Bereich "Reflection" sind meine Kenntnisse leider sehr bescheiden :(

Danke.
 
Zuletzt bearbeitet:

Gregorrr

Bekanntes Mitglied
Frage: Du übergibst irgendein
Code:
Object
und führst über Reflection die Methode
Code:
.getId()
aus -> Warum machst du das? Was ist, wenn du irgendein
Code:
Object
zulässt, was gar keine
Code:
getId()
Methode hat aus? Ist das nicht ein bisschen inkonsistent? Ich mein, im Kontrakt der Methoden-Signatur lässt du alle Objekte zu, aber in der Methode selbst, verlangst du, dass das Objekt diese Methode besitzt. => Entweder
Code:
Id
übergeben, oder
Code:
T extends
irgendein Interface, was die Methode definiert.

Nichts desto trotz, könntest du, ungefähr sowas machen, d.h. eine Klassen Instanz übergeben, bspw.

Java:
public <T> void delete(T object, Class<T> clazz) {
...
em.find(clazz, id);
übergeben.

Dies ist nötig, da durch Type erasure, der dynamische Typ nicht ermittelt werden kann und der nicht als Parameter übergeben werden kann. Generics == statisch, Methodenaufruf == dynamisch
 
S

SlaterB

Gast
wenn T object übergeben wird, dann kann man aus object auch die Klasse als Class<T> holen, welche Klasse sollte es sonst sein?
ein zweiter Parameter dazu wäre unnötig, bei Id + Class schon eher denkbar, aber hier hat man wohl das Objekt
 

fsicher

Bekanntes Mitglied
Erstmal vielen Dank.

Folgende Methode habe ich schon:


Java:
public <T> void delete(Class<T> type, int id) {

		final EntityManager em = Util.getEntityManagerFactory()
				.createEntityManager();

		try {
			em.getTransaction().begin();
			T o = em.find(type, id);

			if (o != null) {
				em.remove(o);
				// ... 
			}

		} catch (Exception e) {
			// ...

		} finally {
			// ... 
		}
	}

Und, da habe ich das Problem mit der Warnung nicht. Nun würde ich gerne beim Aufruf der Methode nur einen Parameter übergeben, falls möglich ...

Du übergibst irgendein Object und führst über Reflection die Methode .getId() aus -> Warum machst du das?

Deine Frage ist mehr als berechtigt. Ich mache es deshalb, weil ich relativ viele Entity-Klassen habe und für jede Entity-Klasse wird eine Klasse erstellt, die sich mit dem Zugriff auf die Db befasse soll: speichern, löschen, suchen nach unterschiedlichen Kriterien etc. Da das Speichern, Löschen, Suche nach Id oder Suche von allen Instanzen einer Klasse immer gleich geht, möchte ich diese Methoden in eine übergeordnete Klasse auslagern: so könnte ich die restlichen Zugriffsmethoden jeweilis in eine separate Klasse unterbringen, die von der übergeordneten Klasse ablegeitet wird und somit die generischen Methoden durch die Vererbung bekommt. Das ist die Motivation.

... oder T extends irgendein Interface, was die Methode definiert

Es kandelt sich um Entity-Klassen wie Person, Adresse, Fahrrad, Miete etc. Ich wüsste jetzt nicht, wie ich hier ein Interface sinnvoll ins Spiel bringen könnte und wäre um jeden Tipp dankbar.

Ein weiterer Punkt betrifft die Methode merge des EntityManagers. Ich bekomme das Objekt als Parameter: Das Objekt wurde zuvor aus der Db mit einem anderen EntityManager geholt, hat die Id und ist "detached". Wenn ich das Objekt dem neuen EntityManager hinzufügen versuche, klappt dies irgendwie nicht:

Java:
... 
em.getTransaction().begin();
em.merge(object);
em.remove(object); // Ausnahme!!!

Beim Aufruf der Methode "remove" wird Ausnahme geworfen:

Java:
java.lang.IllegalArgumentException: Entity must be managed to call remove: Adresse[id=4, xxx ], try merging the detached and try the remove again.

Ich war der Meinung, dass eine "detached" Entity durch "merge" dem Persistenzkontext eines neuen EntityManager hinzugefügt werden kann, aber sieht nicht danach aus. Wie macht man es richtig? Es wäre gut, wenn ich das Objekt nicht zuerst in der Db suchen müsste ...

Danke für jeden Tipp.
 
S

SlaterB

Gast
merge hat anscheinend einen Rückgabewert, der nicht exakt das vorherige Objekt sein muss
 

fsicher

Bekanntes Mitglied
Genau das war es. Wenn ich den Rückgabewert abfange und es anschliessend entferne, funktioniert es.

Java:
... 
em.getTransaction().begin();
T temp = em.merge(object);
em.remove(temp);

Vielen Dank.
 
S

SlaterB

Gast
Es kandelt sich um Entity-Klassen wie Person, Adresse, Fahrrad, Miete etc. Ich wüsste jetzt nicht, wie ich hier ein Interface sinnvoll ins Spiel bringen könnte und wäre um jeden Tipp dankbar.
ein Interface ist für die Gemeinsamkeiten da, wenn das bisher nur die getId()-Methode ist,
dann nenne das Interface Identifiable, IdItem oder DBObject, oder MyEntity, wobei man 'My' eher vermeiden sollte,
ist ganz egal, schadet nicht, vermeidet Reflection und verhindert falsche Objektübergabe
 

Gregorrr

Bekanntes Mitglied
ein Interface ist für die Gemeinsamkeiten da, wenn das bisher nur die getId()-Methode ist,
dann nenne das Interface Identifiable, IdItem oder DBObject, oder MyEntity, wobei man 'My' eher vermeiden sollte,
ist ganz egal, schadet nicht, vermeidet Reflection und verhindert falsche Objektübergabe

+2; Du führst also ein Interface auf einem Abstraktionslevel für die DB ein. Genau das ist der Zweck von Interfaces, dass sie bestimmte Merkmale abkapseln (Abstrahieren bestimmte Merkmale ==Methode), die nur für die Methode von Bedeutung sind == andere Abstraktionsebene.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
N Annotation an felder oder methoden setzten? Data Tier 11

Ähnliche Java Themen

Neue Themen


Oben