Ich habe gerade ein Problem mit dem Wegschreiben von Instanzen in die Datenbank wobei ich den Entitymanager von JPA 2.0 verwenden möchte.
Die Instanz um die es geht hat intern eine Liste (ein HashSet) mit Kind-Instanzen.
Also z.B. in der Art:
Mother mother = new Mother();
mother.addChild(new Child("child #1"));
mother.addChild(new Child("child #2"));
Jedesmal, wenn per mother.addChild() ein Kind hinzugefügt wird, wird dessen setMother() Methode aufgerufen und eine Verbindung zur Mother Instanz hergestellt.
Nun kann es aber passieren, dass zum Beispiel "child #2" bereits in der Datenbank existiert. Daher suche ich in der Datenbank zuerst nach den vorhandenen Kindern, wenn ich welche finde, dann werden diese sofort der Mutter zugewiesen mother.addChild(childFromDatabase). Neue Kinder werden per "mother.add(new Child(child #n))" wie oben gezeigt hinzugefügt.
Jetzt habe ich mal zwei Alternative durchgespielt:
Zum einen verwende ich den
a) JPA EntityManager und konfiguriere ihn über eine Hibernate Konfiguration.
b) Beim zweiten mal nehme ich den EntityManager und benutze aber eine reine JPA 2.0 Konfiguration.
Das Object "mother", dass ich in die Datenbank schreiben möchte, lässt sich nur mit a) persistieren (also plain Hibernate)
Über b) bekomme ich ein "detached entity passed to persist error" und damit ist eins der Kinder gemeint, dass sich bereits in der Datenbank befindet.
In beiden Fällen machen ich ein "em.persist(mother)" (em = EntityManager Instanz)
Vielleicht sieht ja jemand was genau das Problem ist. Liegt's an der Transaktion?
Den EntityManager für Hibernate konfigurier ich so:
EntityManager em = Persistence.createEntityManagerFactory("hbm.conf").createEntityManager();
Das ist die Hibernate Konfiguration hbm.conf
[XML]
<hibernate-configuration>
<session-factory name="moreevent">
<!-- postgreSQL configuration -->
<property name="connection.url">${jdbc.url}/${jdbc.db.name}</property>
<property name="connection.driver_class">${jdbc.driver}</property>
<property name="connection.username">${jdbc.user}</property>
<property name="connection.password">${jdbc.password}</property>
<property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
<!-- property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property-->
<!-- Session handling -->
<property name="current_session_context_class">thread</property>
<property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
<property name="hibernate.connection.autocommit">true</property>
<!-- Connection Pool -->
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.timeout">300</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<!-- Debug Ausgaben de/aktivieren -->
<!-- Diese Einstellung aktiviert die Uebergabe der SQL-Statements an log4j -->
<property name="show_sql">true</property>
<!-- Diese Einstellung sorgt bei der SQL-Ausgabe für eine schoene Formatierung.
Siehe auch log4j.xml wo die Log-Einstellungen für Hibernate SQL gesetzt werden.
-->
<property name="format_sql">true</property>
<!-- Die Einstellung ergaenzt einen Kommentar, der anzeigt durch welche HQL oder Criteria-Abfrage das SQL erzeugt wurde. -->
<property name="use_sql_coments">true</property>
<!-- Annotation - Mapping -->
<property name="transaction.auto_close_session">true</property>
<property name="transaction.flush_before_completion">true</property>
</session-factory>
</hibernate-configuration>
[/XML]
Den EntityManager für JPA instanziere ich über Spring's DI
[XML]
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="pgsql_integration_local_testing" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.PostgreSQLDialect" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}/${jdbc.db.name}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
[/XML]
Die Instanz um die es geht hat intern eine Liste (ein HashSet) mit Kind-Instanzen.
Also z.B. in der Art:
Mother mother = new Mother();
mother.addChild(new Child("child #1"));
mother.addChild(new Child("child #2"));
Jedesmal, wenn per mother.addChild() ein Kind hinzugefügt wird, wird dessen setMother() Methode aufgerufen und eine Verbindung zur Mother Instanz hergestellt.
Java:
class Mother {
public void addChild(Child child) {
this.children.add(child);
child.setMother(this);
}
}
Nun kann es aber passieren, dass zum Beispiel "child #2" bereits in der Datenbank existiert. Daher suche ich in der Datenbank zuerst nach den vorhandenen Kindern, wenn ich welche finde, dann werden diese sofort der Mutter zugewiesen mother.addChild(childFromDatabase). Neue Kinder werden per "mother.add(new Child(child #n))" wie oben gezeigt hinzugefügt.
Jetzt habe ich mal zwei Alternative durchgespielt:
Zum einen verwende ich den
a) JPA EntityManager und konfiguriere ihn über eine Hibernate Konfiguration.
b) Beim zweiten mal nehme ich den EntityManager und benutze aber eine reine JPA 2.0 Konfiguration.
Das Object "mother", dass ich in die Datenbank schreiben möchte, lässt sich nur mit a) persistieren (also plain Hibernate)
Über b) bekomme ich ein "detached entity passed to persist error" und damit ist eins der Kinder gemeint, dass sich bereits in der Datenbank befindet.
In beiden Fällen machen ich ein "em.persist(mother)" (em = EntityManager Instanz)
Vielleicht sieht ja jemand was genau das Problem ist. Liegt's an der Transaktion?
Den EntityManager für Hibernate konfigurier ich so:
EntityManager em = Persistence.createEntityManagerFactory("hbm.conf").createEntityManager();
Das ist die Hibernate Konfiguration hbm.conf
[XML]
<hibernate-configuration>
<session-factory name="moreevent">
<!-- postgreSQL configuration -->
<property name="connection.url">${jdbc.url}/${jdbc.db.name}</property>
<property name="connection.driver_class">${jdbc.driver}</property>
<property name="connection.username">${jdbc.user}</property>
<property name="connection.password">${jdbc.password}</property>
<property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
<!-- property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property-->
<!-- Session handling -->
<property name="current_session_context_class">thread</property>
<property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
<property name="hibernate.connection.autocommit">true</property>
<!-- Connection Pool -->
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.timeout">300</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<!-- Debug Ausgaben de/aktivieren -->
<!-- Diese Einstellung aktiviert die Uebergabe der SQL-Statements an log4j -->
<property name="show_sql">true</property>
<!-- Diese Einstellung sorgt bei der SQL-Ausgabe für eine schoene Formatierung.
Siehe auch log4j.xml wo die Log-Einstellungen für Hibernate SQL gesetzt werden.
-->
<property name="format_sql">true</property>
<!-- Die Einstellung ergaenzt einen Kommentar, der anzeigt durch welche HQL oder Criteria-Abfrage das SQL erzeugt wurde. -->
<property name="use_sql_coments">true</property>
<!-- Annotation - Mapping -->
<property name="transaction.auto_close_session">true</property>
<property name="transaction.flush_before_completion">true</property>
</session-factory>
</hibernate-configuration>
[/XML]
Den EntityManager für JPA instanziere ich über Spring's DI
[XML]
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="pgsql_integration_local_testing" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.PostgreSQLDialect" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}/${jdbc.db.name}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
[/XML]
Zuletzt bearbeitet: