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.
Related
I'm trying to use Hibernate to create a table in a SQL Server 2012 database.
I set a number of properties in my Java project's persistence.xml file:
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServer2012Dialect" />
<property name="hibernate.hbm2ddl.auto" value="auto" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="false" />
<property name="hibernate.use_sql_comments" value="false" />
... and set the database connection details in when UI create my data source, which is done in a configuration Java class:
dataSource.setDriverClassName(myDriver); // com.microsoft.sqlserver.jdbc.SQLServerDriver
dataSource.setUrl(myUrl); // jdbc:sqlserver://host:port;DatabaseName=dbname
dataSource.setUsername(myUser);
dataSource.setPassword(myPwd);
In the Java class, I also set the default schema when I create the Java Persistence entity manager factory:
final Map<String, Object> jpaProperties = new HashMap<>();
jpaProperties.put("hibernate.default_schema", "mySchema");
entityManagerFactory.setJpaPropertyMap(jpaProperties);
entityManagerFactory.afterPropertiesSet();
return entityManagerFactory.getObject();
The Java domain class has been annotated as follows:
#Entity
#Table(name = "mytable")
public class MyTable {
...
}
The schema called "mySchema" has been created in the SQL Server database and authorization has been granted to the user specified in the data source.
When I try and run the functionality which should create the table as part of the first run (and populate it appropriately), I get the following error message:
SQLServerException: Invalid object name 'mySchema.mytable'
... and the table has not been created in the schema.
The Hibernate SQL looks like this:
select alias0_.ID as alias1_0_0_
... other columns...
from mySchema.mytable alias0_
where alias0_.ID=?
I'm using version 1.0.0.Final of the hibernate-jpa-2.1-api JAR in my Java project.
Thanks in advance for any assistance.
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.
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'm using Hibernate's JPA-Implementation to access our SQL Server 2012 database.
When trying to select a nvarchar field in a native query, I get an exception "No Dialect mapping for JDBC type: -9".
It looks much like No Dialect mapping for JDBC type: -9 with Hibernate 4 and SQL Server 2012 or No Dialect mapping for JDBC type: -9 but I couldn't find a solution for me there (both are not using JPA).
My database setup:
CREATE TABLE NvarcharExample(
exampleField nvarchar(20) PRIMARY KEY
)
INSERT INTO NvarcharExample(exampleField) VALUES ('hello')
My code:
import java.io.IOException;
import javax.persistence.*;
#Entity
class NvarcharExample {
#Id
public String exampleField;
}
public class NvarcharTest {
public static void main(String[] args) throws IOException, InterruptedException {
String queryString = "SELECT e.exampleField FROM NvarcharExample e";
// establish connection
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("persistenceUnit");
try {
EntityManager entityManager = entityManagerFactory.createEntityManager();
// access data using JPQL
entityManager.createQuery(queryString).getResultList(); // works
// access data using SQL (native query)
entityManager.createNativeQuery(queryString).getResultList(); // fails
} finally {
entityManagerFactory.close();
}
}
}
My persistence.xml
<?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="persistenceUnit">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<!-- database connection settings -->
<property name="javax.persistence.jdbc.driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
<property name="javax.persistence.jdbc.url" value="jdbc:sqlserver://<servername>:<port>;databaseName=<databasename>" />
<property name="javax.persistence.jdbc.user" value="<user>" />
<property name="javax.persistence.jdbc.password" value="<password>" />
</properties>
</persistence-unit>
</persistence>
With sql logging enable, I get this output in my console
select nvarcharex0_.exampleField as col_0_0_ from NvarcharExample nvarcharex0_
SELECT e.exampleField FROM NvarcharExample e
I'm using
hibernate-core-4.3.10.Final.jar
hibernate-entitymanager-4.3.10.Final.jar
hibernate-jpa-2.1-api-1.0.0.Final.jar
hibernate-commons-annotations-4.0.5.Final.jar
sqljdbc41.jar
What I've tried:
using a varchar instead of nvarchar makes it work, but I need nvarchar
using jpql instead of sql works (see my example code), but I need a native query
I tried sqljdbc4.jar in Version 4.0 and 4.1 and I tried sqljdbc41.jar
I head about subclassing the SQL Server Dialect class, but did not have any success with that
I added <property name="dialect" value="org.hibernate.dialect.SQLServerDialect" /> to my persistence.xml (right behind the password property)
I added <property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect" /> to my persistence.xml
I changed the persistence provider to <provider>org.hibernate.ejb.HibernatePersistence</provider>
Using #Nationalized attribute helped me to map String to nvarchar for MS SQL 2012 without dialect subclassing.
At the same time setting the hibernate.use_nationalized_character_data property to true did not worked for me.
For futher information watch docs National Character Types.
I was able to resolve that issue by subclassing the SQLServerDialect:
package packagename;
import java.sql.Types;
public class SqlServerDialectWithNvarchar extends org.hibernate.dialect.SQLServerDialect {
public SqlServerDialectWithNvarchar() {
registerHibernateType(Types.NVARCHAR, 4000, "string");
}
}
and referencing it in my persistence.xml:
<property name="hibernate.dialect" value="packagename.SqlServerDialectWithNvarchar" />
PS: It seems to be fixed with hibernate 5.1 according to this ticket: https://hibernate.atlassian.net/browse/HHH-10183
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"/>