I have a simple data model which consists of a parent object with a one-to-many relationship to a list of child objects.
#Entity
public class Client implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(cascade = CascadeType.ALL)
private List<Session> sessions;
...
}
#Entity
public class Session implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(length = 200)
private String location;
...
}
I have enabled L2 caching using OpenJpa in 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_Gym" transaction-type="JTA">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<jta-data-source>java:jboss/datasources/GymTracker</jta-data-source>
<class>za.co.blacklemon.entities.Client</class>
<class>za.co.blacklemon.entities.Session</class>
<shared-cache-mode>ALL</shared-cache-mode>
<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"/>
<property name="openjpa.Log" value="File=stdout, DefaultLevel=WARN, Runtime=INFO, Tool=INFO, SQL=TRACE"/>
<property name="openjpa.QueryCache" value="true(CacheSize=10000, SoftReferenceSize=1000)"/>
<property name="openjpa.DataCache" value="true(CacheSize=20000, SoftReferenceSize=1000)"/>
</properties>
</persistence-unit>
</persistence>
I then get individual clients by calling find and then accessing the list of sessions. The second line here triggers OpenJPA to populate the child objects from the DB:
Client client = dao.find(Client.class, id);
System.out.println(client.getSessions().size());
The first time this runs there appears two queries in the log, one for the parent object and one each for any children:
executing prepstmnt 782097742 SELECT t0.contactNumber, t0.description, t0.firstName, t0.photo, t0.surname FROM Client t0 WHERE t0.id = ? [params=?]
executing prepstmnt 626498798 SELECT t1.id, t1.location FROM Client_Session t0 INNER JOIN Session t1 ON t0.SESSIONS_ID = t1.id WHERE t0.CLIENT_ID = ? [params=?]
The second time this runs the initial query is gone, as the object is retrieved from the cache, but the second (and possibly more) query is still executed.
Why does OpenJPA not store the child objects in a one-to-many relationship in the cache?
I'm using OpenJPA 2.3.0 on Java 7.
Why does OpenJPA not store the child objects in a one-to-many relationship in the cache?
OpenJPA stores the child objects, but it doesn't store the FK back into the parent. I fixed this problem in OpenJPA trunk(2.4.x) via OPENJPA-2285.
Related
While attempting to retrieve an Entity from a Database, using JPA's EntityManager, I am getting a ClassCastException that references two identical Classes. After reading other posts/articles, I suspect that the application using 2 different Class Loaders on the same Class type may be the culprit. Unfortunately, I have no idea how to verify nor correct this. Could someone help shine some light on this situation and its solution?
Entity Member.java
package com.example.mysql_flyway_database.entities;
import javax.persistence.*;
#Entity
#Table(name = "_member_")
public class Member {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer memberId;
#Column(name = "member_name")
private String memberName;
public Integer getMemberId() {
return memberId;
}
... // other getter/setter methods
}
persistence.xml - stored in /resources/META-INF/, in case this matters
<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" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="Member" transaction-type="RESOURCE_LOCAL">
<class>com.example.mysql_flyway_database.entities.Member</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url"
value="jdbc:mysql://localhost:3306/JDND_C3"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="Keep1Moving2Forward3!"/>
</properties>
</persistence-unit>
</persistence>
MyApplication
...
private static void readMembersAsEntities(EntityManagerFactory factory) {
EntityManager manager = factory.createEntityManager();
manager.getTransaction().begin();
Member member = manager.find(Member.class, 1);
System.out.println(String.format("Member %s was found", member.getMemberName()));
}
...
Here is the log:
Exception in thread "restartedMain" java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: java.lang.ClassCastException: com.example.mysql_flyway_database.entities.Member cannot be cast to com.example.mysql_flyway_database.entities.Member
at com.example.mysql_flyway_database.MysqlFlywayDatabaseApplication.readMembersAsEntities(MysqlFlywayDatabaseApplication.java:51)
at com.example.mysql_flyway_database.MysqlFlywayDatabaseApplication.main(MysqlFlywayDatabaseApplication.java:42)
... 5 more
Note:
This is quite similar to the issue underlined here:
JPA class loading issue with Hibernate.
Disclosure: I am fairly new to Spring and its plugins/dependencies (currently learning), so I am a bit lost on the provided solution described in the post mentioned. Regarding the solution mentioned in the provided post: In my project, I do not see /WEB-INF/lib.
Any help would be greatly appreciated.
I am trying to develop an app for exercise reasons. I am using MSAccess 2010 as the database with UCanAccess (3.06) as the driver and the EclipseLink 2.1 as the entity framework.
I am stuck in adding new records to the database. Here the error code:
Internal Exception: net.ucanaccess.jdbc.UcanaccessSQLException: UCAExc:::3.0.6 user lacks privilege or object not found: IDENTITY_VAL_LOCAL
Error Code: -5501
Call: SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1
Query: ValueReadQuery(name="SEQ_GEN_IDENTITY" sql="SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1")
It seems to me that the autogenerate of the id fails. The entity class was generated vie Netbeans and looks like this:
#Transient
private PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ID")
private Integer id;
By default, EclipseLink tries to automatically detect the underlying database and generate SQL statements using the appropriate SQL dialect. That apparently isn't working for you because the SQL statement to retrieve the last created identity value is not recognized by UCanAccess .
You could try adding a target-database directive to your EclipseLink configuration specifying SQLServer in an attempt to get a working SQL statement (SELECT ##IDENTITY) to retrieve the last created ID value. However, bear in mind that there are significant differences between T-SQL and Access SQL so you will probably continue to encounter other compatibility issues between EclipseLink and UCanAccess.
before knowing above answer i was also facing same problem for inserting new record in access Database ,
Thanks to Mr. Gord Thompson to give a great Solution for me ,
and it is working too.
i have just added one line in my persistence.xml file..
property name="eclipselink.target-database" value="HSQL"
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="OnePU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>design_frames.One</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:ucanaccess://C:\One\One.accdb"/>
<property name="javax.persistence.jdbc.user" value=""/>
<property name="javax.persistence.jdbc.driver" value="net.ucanaccess.jdbc.UcanaccessDriver"/>
<property name="javax.persistence.jdbc.password" value=""/>
<property name="eclipselink.target-database" value="HSQL"/>
</properties>
</persistence-unit>
</persistence>
I am using JPA and java as technology and writing very simple web application.
There is one class called Employee, look like below code
#Entity
#Table(name="Employee")
public class Employee{
#Id
private int id;
#Column(name="name")
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
one table called Employee is exist into database.
Its persistence.xml file looks like below code.
<?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="JPAService" transaction-type="RESOURCE_LOCAL">
<!-- Persistence provider -->
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<!-- Entity classes -->
<class>com.solution.domain.Employee</class>
<properties>
<!-- The JDBC driver of your database -->
<property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
<!-- The JDBC URL to the database instance -->
<property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/test" />
<!-- The database username -->
<property name="javax.persistence.jdbc.user" value="postgres" />
<!-- The database password -->
<property name="javax.persistence.jdbc.password" value="postgres"/>
<property name="javax.persistence.jdbc.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
</properties>
</persistence-unit>
</persistence>
Employee class entry exist in this xml file.
There are not issue while startup of application. Every thing working fine.
But when query is executed then it throw and exception.
"Employee is not mapped [select e from Employee e]"
EntityManager em = getEntityManager();
em.getTransaction().begin();
Query query = em.createQuery("select e from Employee e");
List<Employee> employees = query.getResultList();
if(employees != null){
return employees.get(0);
}
em.getTransaction().commit();
I am unable to understand where mapping is missing. As i already mentioned its a web project. So for more clarification i am attaching one screen shot of my project too.
Thanks in advance.
I got the problem. It was an silly mistake. I was using JPA but in Employee class I used the Entity annotation from hibernate implementation instead of JPA package.
Side note: It's a bad idea to model the database with JPA, e.g., by implementing the integer surrogate key in the data model. JPA is supposed to help persist an object model, which would use the natural "key" to distinguish objects. A JPA entity should only expose attributes of the object model. This has the benefit of greatly simplifying the expression of relationships because you relate objects, not ID fields. Don't use JPA for database translation, use it for object persistence.
I'm working on a JAVAEE Enterprise application, which has the technology stack: Glassfish 3.1, EJB 3.1, EclipseLink 2.4.2, SQL Server 2008 R2. In the EJB module, I have a couple of entities which use SequenceGenerator's and a couple of entities with TableGenerator's.
The SequenceGenerator's are working fine, but the TableGenerator's aren't. I tried to check the server.log by setting the EclipseLink's logging to 'FINEST', but I don't see any queries logged for getting the next value of the Id. The EJB entity that uses TableGenerator is as below:
#Entity
#Table(name = "TEST")
#TableGenerator(name = "test_gen", table = "ID_GENERATOR", pkColumnName = "ID_NAME", pkColumnValue = "TEST", valueColumnName = "ID_VAL", allocationSize = 50, initialValue = 1)
public class Test extends SuperClass implements Interface1, Interface2, Interface3, Interface4, Interface5, Serializable {
private static final long serialVersionUID = 5084413459400887388L;
/** The id of the entry.
*/
protected long id = 0;
#Id
#GeneratedValue(strategy = GenerationType.TABLE, generator = "test_gen")
#Column(name = "NWTID", nullable = false, updatable = false)
#Override
public long getId() {
return id;
}
.....
}
Note: The Table 'ID_GENERATOR' is used by all entities with TableGenerator annotation, with a Unique Generator name.
After checking the logs with 'FINEST' setting, I tried many other ways, but couldn't get the 'TableGenerator' working. Later, I downloaded the EclipseLink's (2.4.2) sources and debugged the 'Sequencing' mechanism, during deployment, as well as at application runtime. During deployment, I found the Sequence 'TEST' to be initialized, but at runtime, the Id's are not being generated.
BTW, my persistence.xml has a couple of datasources, with the following properties for EclipseLink:
<persistence-unit name="TestCtx" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>TESTDS</jta-data-source>
<properties>
<property name="eclipselink.target-database" value="SQLServer"/>
<property name="eclipselink.query-results-cache" value="false"/>
<property name="eclipselink.cache.shared.default" value="false"/>
<property name="eclipselink.weaving" value="static"/>
<property name="eclipselink.id-validation" value="NULL"/>
<property name="javax.persistence.validation.mode" value="NONE"/>
<property name="eclipselink.ddl-generation" value="create-or-extend-tables"/>
<property name="eclipselink.logging.thread" value="false"/>
<property name="eclipselink.logging.session" value="false"/>
<property name="eclipselink.logging.timestamp" value="false"/>
<property name="eclipselink.logging.exceptions" value="false"/>
</properties>
</persistence-unit>
Do you have any clue, as to what's happening here?
Finally, I found the solution. The culprit is the Eclipse-Link property 'eclipselink.id-validation', defined in the persistence.xml file:
<property name="eclipselink.id-validation" value="NULL"/>
Actually, I knew about this already, that defining this property would stop ID/Sequence generation, as discussed in this thread. But, I thought that this applies, only when the property is set to 'NONE'. In my case, it is set to 'NULL'. Also, SequenceGenerator's are working fine, even when this property is set. So, logically, I thought the TableGenerator's (which use TableSequence - as per EclipseLink's source code) should work, when the property is set to 'NULL'. So, removing this property worked for me.
Also, note that the below property has the same effect on TableGenerator's (Id/Sequence is not generated):
<property name="eclipselink.allow-zero-id" value="true"/>
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.