Can one entity be persisted to multiple persistence units using OpenJPA? - java

I'm trying to save an entity to two separate persistence units one after the other. I can successfully save the entity to the first unit, I then detach it from that unit, reset the #Id value and persist to the second, but it appears that the object still has an associated id that is possibly not set-able? I think it's called the oid? The error:
Caused by: <openjpa-2.2.0-r422266:1244990 nonfatal store error>
org.apache.openjpa.persistence.EntityNotFoundException: The instance
of type "class za.co.core.ejb.entities.Address" with oid "4" no longer
exists in the data store. This may mean that you deleted the instance
in a separate transaction, but this context still has a cached version.
I know I can create a brand new object and copy the values I want across, but I want to do this generically without knowing too much about the object itself.
My code looks like this:
#PersistenceContext(unitName = "puOpenJPA_MSSQL",
type = PersistenceContextType.TRANSACTION)
private EntityManager entityManager;
#PersistenceContext(unitName = "puOpenJPA_MSSQLaudit",
type = PersistenceContextType.TRANSACTION)
private EntityManager auditManager;
...
entityManager.persist(entity);
entityManager.detach(entity);
entity.setId(null); //this sets the #id property of the entity to null
auditManager.persist(entity); //exception thrown
And here is the persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="puOpenJPA_MSSQL" transaction-type="JTA">
<provider>
org.apache.openjpa.persistence.PersistenceProviderImpl
</provider>
<jta-data-source>
java:jboss/datasources/mySqlSandbox
</jta-data-source>
<class>
za.co.core.ejb.entities.AuditableEntity
</class>
<class>za.co.core.ejb.entities.Address</class>
<properties>
<property name="openjpa.jdbc.SynchronizeMappings"
value="buildSchema(ForeignKeys=true)" />
<property name="jboss.as.jpa.providerModule"
value="org.apache.openjpa" />
<property name="openjpa.DynamicEnhancementAgent"
value="false"/>
</properties>
</persistence-unit>
<persistence-unit name="puOpenJPA_MSSQLaudit" transaction-type="JTA">
<provider>
org.apache.openjpa.persistence.PersistenceProviderImpl
</provider>
<jta-data-source>
java:jboss/datasources/mySqlSandboxAudit
</jta-data-source>
<class>za.co.core.ejb.entities.AuditableEntity</class>
<class>za.co.core.ejb.entities.Address</class>
<properties>
<property name="openjpa.jdbc.SynchronizeMappings"
value="buildSchema(ForeignKeys=true)" />
<property name="jboss.as.jpa.providerModule"
value="org.apache.openjpa" />
<property name="openjpa.DynamicEnhancementAgent"
value="false" />
</properties>
</persistence-unit>
</persistence>
Thanks,
Sean

In theory yes because entities are "plain old java objects", but in practice to make all that magic work the persistence provider proxies parts of it, like collection members. As soon as you persist it, its not 'your' entity anymore - its part of the provider's bookkeeping.
If you want to persist the same entity multiple times, clone it multiple times and persist each individual copy.

Related

Injecting EntityManager returns null after Jboss/Wildfly migration

My application is running perfectly fine in JBoss AS 5.1.0. My goal is to migrate it to Wildfly 10.
Below is my persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="ApplicationPersistenceUnit">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/MySQL_DS</jta-data-source>
<jar-file>application_db_interface.jar</jar-file>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="jboss.entity.manager.jndi.name" value="java:/ApplicationPersistenceUnit"/>
<property name="jboss.entity.manager.factory.jndi.name" value="java:/ApplicationPersistenceUnitFactory"/>
</properties>
</persistence-unit>
</persistence>
Below is my transaction manager class;
public class TransactionManager implements TransactionManagerI {
#PersistenceContext(unitName="ApplicationPersistenceUnit")
private EntityManager em;
...
}
I also try to use lookup but it still returns null;
public Session getSession() throws DAOException {
..
em = (EntityManager) new InitialContext().lookup("java:/ApplicationPersistenceUnit");
..
}
Below is the project schema;
->application.ear
->application.ear/application.war
->application.ear/db.jar
->application.ear/db.jar/META-INF/persistence.xml
I looked into other solutions and try one by one but couldn't figure out mine yet. I can provide more info if you need.
UPDATE: I check JNDI view from wildfly admin console. I don't see ApplicationPersistenceUnit there. It looks like server doesn't bind my persistence.xml file. I am now trying to figure out this problem.

How entity manager read new record inserted by others

My application use JPA/hibernate to read data from database. The application is read only, and data is inserted by other program.
The problem is that my application can only read flesh data in the first time. When new data is inserted by other program, my application cannot see it.
Here is my test code:
public class TestJpaRead {
private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("org.hibernate.tutorial.jpa");
public static void main(String[] args) {
LOG.debug("first time");
countRow(); //output row size = X
//set break point here, and manually insert an new row by using mysql client
LOG.debug("second time");
countRow(); //should output row size = X + 1, but it is still X
}
public static void countRow() {
EntityManager em = emf.createEntityManager();
Query query = em.createQuery("SELECT a FROM " + Report.class.getSimpleName() + " a");
List result = query.getResultList();
LOG.debug("countRow: {}", result.size());
em.close();
}
}
and here is my persistence.xml (nothing special):
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="org.hibernate.tutorial.jpa" transaction-type="RESOURCE_LOCAL">
<description>
Persistence unit for the JPA tutorial of the Hibernate Getting Started Guide
</description>
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/foo" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.password" value="bar" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="auto" />
</properties>
</persistence-unit>
Thanks!
From MySQL query log, I find the reason of the problem:
48 Query SET autocommit=0
140606 11:35:41 48 Query select report0_.id from Report report0_ /*countRow()*/
48 Query SHOW WARNINGS
140606 11:35:42 48 Query select report0_.id from Report report0_ /*countRow()*/
48 Query SHOW WARNINGS
Hibernate does not work in the autocommit mode by default.
em.close() does not implicit commit or rollback the transaction, i.e., the JDBC connection and transaction is still alive/open.
This is what I misunderstood. (emf.close() will actually close the connection.)
When you get EntityManager from emf.createEntityManager(), the new
EntityManager may reuse old JDBC connection. It means that you may
in the transaction opened by previous closed EntityManager.
When you are in a uncommit/opened transaction, and use the default
MySQL isolation level, you cannot see change made by others.
Solution: explicit open and commit the transaction, or tell Hibernate to allow autocommitted JDBC connections. Refs: Select using hibernate

No Entity metadata found for the class

I'm back with the same problem ...
I'm trying to uses queries in my Cassandra DB with Kundera (Cassandra ORM), this queries work in an others project but when I try to do it in webapp (using tomcat 6.0), I got this error :
com.impetus.kundera.metadata.KunderaMetadataManager - No Entity metadata found for the class
=> JavaNullPointerException.
But when I leave the persistence.xml from my project I got an other error. (NoPersistence.xml found or something ... )
So, my project found Persistence.xml, but not my Entity class : fileCassandra.
You can see my persistence.xml :
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<!-- 192.168.3.107 -->
<persistence-unit name="cassandra_pu">
<provider>com.impetus.kundera.KunderaPersistence</provider>
<class>net.***.common.db.***.FileCassandra</class>
<properties>
<property name="kundera.nodes" value="localhost"/>
<property name="kundera.port" value="9160"/>
<property name="kundera.keyspace" value="KunderaExamples"/>
<property name="kundera.dialect" value="cassandra"/>
<property name="kundera.client.lookup.class" value="com.impetus.client.cassandra.pelops.PelopsClientFactory" />
<property name="kundera.cache.provider.class" value="com.impetus.kundera.cache.ehcache.EhCacheProvider"/>
<!-- <property name="kundera.cache.config.resource" value="/ehcache-test.xml"/> -->
</properties>
</persistence-unit>
</persistence>
net..common.db..FileCassandra I must replace by * because it's name from my companie ;)
The same methods (include EntityManager) works in junit on other project, when I build my project in Tomcat, this error appears ...
This happens when you have multiple entries of the same class in your classpath.
The ideal place to have your entities is closest to the same class loader which loads kundera core and client(HBase, Cassandra etc.).
For example, if these kundera files are under WEB-INF/lib, you'd rather have your entities under the application where as if kundera files are on the applications lib folder, better bundle your entities in a jar and put them there (and remove the entities in your app).
Only issue which i can see is classes and persistence.xml location.
try to place persistence.xml within /WEB-INF/classes/META-INF/, Provided that your entity definitions are within classes folder!
-Vivek

DDL generation and general persistence.xml settings (OpenJPA)

Summary
I'm trying to run a Java web application JPA 2.0 example. The example application was written to run in Glassfish, using EclipseLink as JPA provider.
I would like to convert it to run in TomEE with OpenJPA as the JPA provider, but I can't any detailed tutorials for getting up and running with OpenJPA.
Problem
I'm having trouble converting persistence.xml to work with OpenJPA instead of EclipseLink. More specifically, the given persistence.xml doesn't specify:
Entity classes. Are these necessary?
The desired JPA provider. Will the container default to something?
The JDBC driver. How do I specify an "in-memory" DB (just for initial testing purposes)?
Also:
How are the DDL generation properties expressed in OpenJPA? I wasn't able to find them the OpenJPA User Guide.
Details
Below is the EclipseLink persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="order" transaction-type="JTA">
<jta-data-source>jdbc/__default</jta-data-source>
<properties>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
<property name="eclipselink.ddl-generation.output-mode"
value="both" />
</properties>
</persistence-unit>
</persistence>
I have the following Entity classes:
order.entity.LineItem
order.entity.LineItemKey
order.entity.Order
order.entity.Part
order.entity.PartKey
order.entity.Vendor
order.entity.VendorPart
Question
Does anyone know what the equivalent persistence.xml would look like for OpenJPA?
Alternatively, if anyone could point me to an OpenJPA tutorial that covers these issues that would be just as good
If you add the openjpa.jdbc.SynchronizeMappings property as shown below OpenJPA will auto-create all your tables, all your primary keys and all foreign keys exactly to match your objects
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
Alternatively, you can use EclipseLink in TomEE by just adding the EclipseLink jars to <CATALINA_HOME>/lib/
refer here for Common PersistenceProvider properties
Foreign key constraints
The next line does not create foreign keys:
<property name="openjpa.jdbc.SynchronizeMappings"
value="buildSchema(ForeignKeys=true)"/>
Only creates schema and deletes content of a database.
But if you want create foreign keys, use the following lines:
<property name="openjpa.jdbc.SynchronizeMappings"
value="buildSchema(foreignKeys=true,schemaAction='dropDB,add')"/>
<property name="openjpa.jdbc.SchemaFactory"
value="native(foreignKeys=true)" />
<property name="openjpa.jdbc.MappingDefaults"
value="ForeignKeyDeleteAction=restrict, JoinForeignKeyDeleteAction=restrict"/>
See generated SQL
In another way, if you want to see the SQL output:
<property name="openjpa.Log"
value="DefaultLevel=TRACE,SQL=TRACE" />
NOTE: In order to see the generated output in the TomEE console, you need to change the log level in the file loggin.properties with openjpa.level = FINEST
See more in http://openjpa.apache.org/faq.html

Two Persistence Unit in one Persistence.xml

We created some libraries that all our projects will use, this libraries will provide the basic functionality of all our systems (login, some manage, etc). But the application itself could use another database.
What we did was to create the Persistence.xml with two persist units. And package all the core library entities in a jar called "LN-model.jar" and all of the entities of out test app in "App-model.jar". But for some reason we still obtain the following message.
Could not resolve a persistence unit corresponding to the persistence-context-ref-name [x.x.x.x.listener.InicializadorListener/em] in the scope of the module called [gfdeploy#/Users/zkropotkine/WORK/SeguridadCore/dist/gfdeploy/SeguridadCore-war_war]. Please verify your application.
Here's our Persistence.xml
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="x" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/x</jta-data-source>
<jar-file>App-model.jar</jar-file>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
</properties>
</persistence-unit>
<persistence-unit name="y" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/y</jta-data-source>
<jar-file>LN-model.jar</jar-file>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties/>
</persistence-unit>
By the way we put the Persistence.xml in a jar, that we add to our Enterprise Project (EAR).
The problem is that the JPA does not know which is the persistence unit to use. when you have only one persistence unit this problem does not occur. To fix do the following:
You need to specify a persistence unit : #PersistenceContext(unitName="...") in the Ejb that do not have
You can add the annotations:
#PersistenceUnit(name = "x")
EntityManagerFactory entityManagerFactory;
#PersistenceContext(unitName = "y")
EntityManager entityManager;
Or you can create it manually:
EntityManagerFactory emfA = Persistence.createEntityManagerFactory("x", properties);
EntityManagerFactory emfB = Persistence.createEntityManagerFactory("y", properties);
For more details, please see the following link: https://docs.oracle.com/html/E25034_01/usingmultipledbs.htm
is very useful, to me helped me!

Categories