EclipseLink and TableGenerator - Id not generated - java

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"/>

Related

How to add missing columns in a multi-schema based multi-tenant web app using eclipselink

I'm developing a multi-tenant web app with "Shared Database/Separate Schemas" approach using java, jpa(eclipselink), mysql. My persistence file looks like:
<persistence-unit name="GroupBuilderPU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.cache.shared.default" value="false"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/?"/>
<property name="eclipselink.ddl-generation" value="create-or-extend-tables"/>
<--- Here goes other properties definition -->
</persistence-unit>
Now here is my EntityMangerFactory and EntityManager:
emfForTenant = Persistence.createEntityManagerFactory("GroupBuilderPU");
EntityManager em = emfForTenant.createEntityManager();
em.setProperty("eclipselink.tenant-id", schemaNameAsTenantId);
Its working fine untill I'm adding any new persistence column in any entity.
Like I've a Entity UserAccount where I've added a new column 'String rentalinfo' :
#Entity
#Multitenant(MultitenantType.TABLE_PER_TENANT)
#TenantTableDiscriminator(type = TenantTableDiscriminatorType.SCHEMA, contextProperty = PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT)
public class UserAccount implements Serializable {
...
private String rentalinfo;//Newly added column
...
}
Now after that this the following line is giving error:
em.createQuery("SELECT ua FROM UserAccount ua").getResultList();
The error is:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'RENTALINFO' in 'field list'
So what will be the solution for adding new column (extend table) in this approach?
You are getting this exception because the 'RENTALINFO' column does not exist on your UserAccount table. Under normal circumstances, setting "create-or-extend-tables" will have EclipseLink issue an ALTER to your existing table, adding the new column. However, it would appear ddl generation is not supported for MultitenantType.TABLE_PER_TENANT: https://wiki.eclipse.org/EclipseLink/DesignDocs/Multi-Tenancy/TablePerTenant
Not supported:
Schema generation will not be supported since it requires knowledge of all the tenants (schema's) and further to that, access provision must be set once the tables are created if using schema level table per tenant.
So there is no ALTER and your table does not have the column.
As a side note, you can turn on EclipseLink SQL logging using the following persistence properties:
<properties>
<property name="eclipselink.logging.level" value="ALL"/>
<property name="eclipselink.logging.level.sql" value="FINE"/>
<property name="eclipselink.logging.parameters" value="true"/>
</properties>
This way, you can see what queries EclipseLink is (or in this case, isn't) executing.

Identity Generation with MySql and H2 for local testing

I'm new here, so I hope it's not a stupid question.
I am using a MySQL DB and am trying to use an H2 DB alongside for local tests. I am running into problems when persisting new objects, i.e., objects that do not yet have an Id. It works fine on the running system using MySQL, but currently the local tests in H2 fail with the following exception:
javax.persistence.PersistenceException: org.hibernate.HibernateException: The database returned no natively generated identity value
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1377)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1300)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1306)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:871)
...
Caused by: org.hibernate.HibernateException: The database returned no natively generated identity value
at org.hibernate.id.IdentifierGeneratorHelper.getGeneratedIdentity(IdentifierGeneratorHelper.java:90)
at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:100)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:58)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2936)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3447)
at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:81)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:362)
at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:203)
at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:183)
at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:167)
at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:320)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:287)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:126)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:78)
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:208)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:151)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:78)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:843)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:818)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:822)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:865)
... 33 more
I use the following persistence annotations in the corresponding Java class:
#Entity
#Table( name = "myclass" )
public class MyClassDbo {
private MyClassId id;
#Id
#Column( nullable = false )
#GeneratedValue( strategy = GenerationType.AUTO )
#Type( type=MyClassIdType.FQ_CLASS_NAME )
public MyClassId getId() {
return this.id;
}
...
}
The persistence configuration looks like this. For production:
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.url" value="jdbc:mysql://#my.db.host#/#my.db.schema#"/>
<property name="hibernate.connection.username" value="#my.db.user#"/>
<property name="hibernate.connection.password" value="#my.db.password#"/>
For local tests:
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<property name="hibernate.connection.driver_class" value="org.h2.Driver"/>
<property name="hibernate.connection.url" value="jdbc:h2:mem:db1;MODE=MySQL;DB_CLOSE_DELAY=-1;MVCC=true;INIT=create schema IF NOT EXISTS generic" />
<property name="hibernate.connection.username" value="sa"/>
<property name="hibernate.connection.password" value=""/>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
The MySQL DB is setup with the following SQL:
CREATE TABLE MYCLASS
( ID BIGINT PRIMARY KEY AUTO_INCREMENT, ... )
The H2 DB is setup using a testdata.xml
<?xml version='1.0' encoding='UTF-8'?>
<dataset>
<MYCLASS ID="1" .../>
</dataset>
with the following code
JdbcDatabaseTester databaseTester = new JdbcDatabaseTester( "org.h2.Driver", "jdbc:h2:mem:db1;MODE=MySQL;DB_CLOSE_DELAY=-1;MVCC=true;INIT=create schema IF NOT EXISTS generic;", "sa", "" );
File file = new File( "testdata.xml" );
databaseTester.setDataSet( new FlatXmlDataSetBuilder().build( file ) );
databaseTester.setSetUpOperation( DatabaseOperation.CLEAN_INSERT );
databaseTester.setTearDownOperation( DatabaseOperation.NONE );
return databaseTester;
and when I look into the H2 DB, everything looks correct to me, the ID column is marked to be the primary key and has a default value which generates an ID.
I am using the following versions:
Java 7
MySQL Connector 5.1.40
Hibernate 4.1.9
H2 1.3.173
DB Unit 2.4.9
I have not found a way to make MySQL and H2 work together here. I have tried different GenerationTypes and the only idea I have right now is to create my own IdentityGenerator which depending on the setup either manually creates an Id for the H2 DB or behaves like the standard IdentityGenerator for MySQL. However, with this I deploy code dedicated for testing into the running system which I would like to avoid.
Thanks for any ideas and suggestions! And please tell me if I forgot any important information.

Error with persistence using EclipseLink and UCanAccess

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>

OpenJPA L2 Cache not caching related objects

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.

Hibernate can't instantiate id generator in Spring project with multiple data sources

I have a Spring project using Hibernate with two data sources (db2 and sql-server).
As soon as I add
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SOME_SEQ")
to a column field in my entity class, I get a BeanCreationException when creating the sql-server EntityManagerFactory because org.hibernate.dialect.SQLServerDialect doesn't support sequences. The only place this entity is being used, though, is in a DAO that uses a db2 EntityManagerFactory which is using the appropriate dialect.
What am I missing?
Try it with GenerationType=AUTO instead of GenerationType=SEQUENCE.
#GeneratedValue(strategy = GenerationType.AUTO, generator = "SOME_SEQ")
With AUTO hibernate uses the best fitting generation strategy, which is sequences for some databases and autoincrement for others.
(N. B.: I never use annotations but I use mapping files. There <generator class="native"> works well for different database types. GenerationType=AUTO should be the same for annotations.)
Even I faced the same issue and solved it by adding the following option to the JPA persistence-unit configuration
<exclude-unlisted-classes>true</exclude-unlisted-classes>
This option forces the JPA provider to only scan the listed classes instead of the whole surrounding jar, etc.
So it now looks like -
<persistence-unit name="MSSQLBackedPersistenceUnit" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/jdbc/MSSQLServerDS</jta-data-source>
<class>com.example.app.domain.MyEntity</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServer2008Dialect" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>

Categories