Hibernate JPA Column "NEXTVAL" not found - java

We changed the JPA provider from EclipseLink to Hibernate 4.1.3. A problem occured when attempting to persist entity using generated id. This gives the following error:
JdbcSQLException: Column "NEXTVAL" not found; SQL statement: select nextval for SCHEMA.ID_SEQ_GENERATOR
The sequence for the entity looks like the following:
#Id
#SequenceGenerator(name = "ID_GENERATOR", initialValue = 100000, allocationSize = 1, sequenceName = "ID_SEQ_GENERATOR")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ID_GENERATOR")
#Column(name = "ID", nullable = false)
public Long getId() {
return this.id;
}
I tried changing the 'strategy = GenerationType.IDENTITY', but it had no effect.
Any advice?

I found out that there are different databases used depending on the environment used. The dialect used is (currently) always the same even though it should change depending on the server the code is executed on. (The correct dialect is actually loaded first, but it then gets replaced because of spring decides to use another class annotated with #Configuration. I think that using profiles should get me past this, though still working with this...)
I found this link which helped me to get on right tracks:
http://techmagik.blogspot.fi/2012/07/sequence-support-in-jpa-for-db2-zos.html.html
Discovering that the H2 was used, I changed the SQL to :
"NEXT VALUE FOR " + sequenceName
Which fixed the error
So the actual problem is with loading correct dialect (as 'Luca Basso Ricci' hinted). The dialect is for DB2 (always), when it should be for H2 in some cases. For some reason this problem manifested when the provider was changed so it made it a bit difficult to track right reason.

Related

Quarkus with Panache getting hibernate error HHH000183

I built an application with Quarkus and I'm using Hibernate with Panache for the models. Everything goes well, the application starts, but when I call a webservice to get a list using Panache functionalities (.listAll()), I get an empty list and I see the following message in the console:
HHH000183: no persistent classes found for query class: from com.myproject.model.TeamEntity
My models are defined with #Entity annotations that should allow Hibernate to find by itself the entity mappings. Here is an example with the Team model:
#Entity
#Table(name = "TEAM")
public class TeamEntity extends PanacheEntityBase {
#Id
#GeneratedValue(strategy = SEQUENCE, generator = "TEAM_SEQ_GEN")
#SequenceGenerator(name = "TEAM_SEQ_GEN", sequenceName = "TEAM_SEQ", allocationSize = 10)
#Column(name = "ID_TEAM", nullable = false)
private int id;
#Column(name = "NAME", nullable = false)
private String name;
...
}
I don't have any persistence.xml file in the project, only the application.properties linked with Quarkus. Here are the relevant properties extracted from mine:
quarkus.datasource.db-kind=oracle
quarkus.datasource.jdbc.url=jdbc:oracle:thin:/#MYWALLET
%dev.quarkus.datasource.jdbc.url=jdbc:oracle:thin:MYUSER/MYPASSWORD#localhost:1521/SAA
quarkus.datasource.jdbc.driver=oracle.jdbc.OracleDriver
quarkus.datasource.jdbc.min-size=2
quarkus.datasource.jdbc.max-size=10
quarkus.datasource.jdbc.new-connection-sql=alter session set current_schema=MYSCHEMA
quarkus.hibernate-orm.dialect=org.hibernate.dialect.Oracle12cDialect
Does someone know where the problem could come from ? Hibernate should detect entities with annotations and use them in queries automatically.
It came out that the problem was on Quarkus Datasource configuration in the application.properties file. More particularly from this specific line to define the schema used at first connection (I have to admit that was not good looking):
quarkus.datasource.jdbc.new-connection-sql=alter session set current_schema=MYSCHEMA
Replacing the line above with the following solved the problem:
quarkus.hibernate-orm.database.default-schema=MYSCHEMA
In conclusion, I think Hibernate cannot find / does not take the entities defined if this property is not defined, maybe because it makes some kind of detection beforehand. That's only a supposition, if someone knows more precisely how Hibernate works for that specific case, I would be very interested !

Hibernate 5 ID AUTO Generation Type for Oracle as Sequence and MySQL as Identity

We have a Java program using Hibernate 5 that can be installed using different DB Engines: Oracle, PostgreSQL or SQL Server. Now we are introducing MySql.
The entities have a Generated Value AUTO identifier.
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
protected Long id;
This worked fine until now. Oracle and PostgreSQL installations are using HIBERNATE_SEQUENCE sequence to generate the id values and SQL Server is using a table generated id (IDENTITY).
With MySQL we would like to use also the table generated id, but Hibernate 5 GenerationType.AUTO on MySQL tries the TABLE generator instead of the IDENTITY generator.
I found this solution by Vlad Mihalcea where using a native generator makes Hibernate to select IDENTITY for MySQL:
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
#GenericGenerator(name = "native", strategy = "native")
protected Long id;
That's nice for MySQL, but then the application is no longer working in Oracle (ORA-02289: sequence does not exist). I think Hibernate is then searching for a sequence called native in the Oracle DB.
Is there a solution to keep the ID generation the same for all the other DB engines (Oracle, PostgreSQL and SQL Server) and use the IDENTITY for MySQL?
If not the only solution I can see is to implement the TABLE ID generation in MySQL, but it seems not to have a good performance.
I almost had it in the question, but in case somebody falls in the same situation: calling the generator HIBERNATE_SEQUENCE will make it backwards compatible with Oracle and PostgreSQL (SQL Server will continue using IDENTITY).
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "HIBERNATE_SEQUENCE")
#GenericGenerator(name = "HIBERNATE_SEQUENCE", strategy = "native")
protected Long id;
Hey this question/answer got me on the road to the answer. I am using Hibernate core 5.4.30 with MSSQL SQLServer2012Dialect and Oracle Oracle12cDialect. I needed to use the #GenericGenerator annotation as well for it's native strategy. maybe I could have used this directly with #GeneratedValue? anyway...
I found Oracle did not come with a sequence named HIBERNATE_SEQUENCE, and even when I added one, hibernate was still giving me sequence not found errors, seemingly having to do with my schema... So you can make things more specific like this:
#Id
#GenericGenerator(name = "MY_SEQUENCE", strategy = "native",
parameters = {
#org.hibernate.annotations.Parameter(name = "schema", value="MY_SCHEMA"),
#org.hibernate.annotations.Parameter(name = "sequence_name", value="MY_SEQUENCE")
}
)
#GeneratedValue(generator = "MY_SEQUENCE")
private Long id;
Hypothetically the name of the #GenericGenerator only has to match the generator name in the #GeneratedValue, but I made it the same as my actual database sequence for simplicity.

Oracle JPA GenerationType.AUTO with generator asks for "hibernate_sequence"

I'm trying to use a defined sequence generation in Oracle JPA, along with GenerationType.AUTO like this:
#Id
#SequenceGenerator(name = "MY_GEN_NAME", sequenceName = "MY_SQ_NAME")
#GeneratedValue(strategy = GenerationType.AUTO, generator = "MY_GEN_NAME")
#Column(name = "ID", nullable = false)
private Long id;
After running the hibernate validation it throws an error:
Schema validation: missing sequence [hibernate_sequence]
I guess, it is ignoring my MY_GEN_NAME and trying to use that global sequence for id generation.
When I switch to GenerationType.SEQUENCE, it uses SequenceHiLoGenerator and it works fine.
Why is that happening, and is it possible to make the GenerationType.AUTO work with given sequence for Oracle (possibility to switch to other db)?
AUTO says to the JPA provider, "choose what you want", and it will not use the "generator" attribute in that case.
If you want to use a SEQUENCE then set the strategy to SEQUENCE! That way it will use the sequence definition you have defined
Though hibernate-sequence-on-oracle-generatedvaluestrategy-generationtype-auto suggests that this will work, it appears that it is broken for some versions of Hibernate, see HHH-10656.
Edit: Broken in 5.2.0, unbroken in 5.2.8.

JPA GenerationType.AUTO not considering column with auto increment

I have a table with a simple int id column with Identity auto increment in SQL Server.
The entity's Id is annotated with #Id and #GeneratedValue
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", length = 4, precision = 10, nullable = false)
private Integer id;
In SQL Server the column is properly set as Identity with Seed and Increment equals to 1.
When I try to persist an instance of this entity, Hibernate tries to query the hibernate_sequence table to obtain the ID value. Since I haven't created that table in my schema I'm getting an error:
could not read a hi value: com.microsoft.sqlserver.jdbc.SQLServerException: Invalid object name 'MySchema.hibernate_sequence'
If I change the generation type to IDENTITY everything works as expected
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", length = 4, precision = 10, nullable = false)
private Integer id;
I cannot change it this way, since my App will run both on MS SQL and ORACLE, and the latter does not support auto incremented columns.
As far as I know the AUTO type should use the auto increment behaviour if the underlying database has support to it, so I don't know why is not working.
UPDATE:
It took me some time but I was able to understand exactly what is going on.
I am working with legacy databases with the following behaviours:
MSSQL: id generation uses table IDENTITY
ORACLE: id generation uses a trigger. The trigger queries and updates a custom table where all the "next ids" are stored. This table is called SEQ.
Here is the outcome of using some id generation strategies:
AUTO: does not work in MSSQL, as explained above
IDENTITY: works in MSSQL but is not supported by Oracle
"native": works in MSSQL but fails in ORACLE. It fails because Hibernate activates its default sequence strategy, which uses hibernate_sequences.nextval. Since this is a legacy application the values from the SEQ table (mentioned above) and the hibernate_sequences are not synchronized (SEQ's value for that particular table is at 6120, and hibernate_sequences' is at 1, which is expected since it was not used until now).
So what I need to figure out is a way to configure that entity to:
Use MSSQL Identity feature
OR
When using Oracle, do not automatically set any value to the ID variable and leave everything up to the pre-existing trigger
This can cause me serious issues on Oracle when I need to insert entities that depend on the main entity (via foreign key), because Hibernate won't know which ID value was generated by the "external" trigger.
I had a similar problem and found this information (deeper explained in here).
Adding this property into my persistence.xml file fixed the issue:
<property name="hibernate.id.new_generator_mappings" value="false" />
Orcale 12c supports IDENTITY and SQL SERVER 2012 supports SEQUENCES. I believe a SEQUENCE is always a better choice than an IDENTITY. IDENTITY disables batching and SEQUENCES allow you to provide optimizers, such as the pooled-lo optimization strategy.
This is how the actual identifier generator is chosen for the configured GenerationType value:
switch ( generatorEnum ) {
case IDENTITY:
return "identity";
case AUTO:
return useNewGeneratorMappings
? org.hibernate.id.enhanced.SequenceStyleGenerator.class.getName()
: "native";
case TABLE:
return useNewGeneratorMappings
? org.hibernate.id.enhanced.TableGenerator.class.getName()
: MultipleHiLoPerTableGenerator.class.getName();
case SEQUENCE:
return useNewGeneratorMappings
? org.hibernate.id.enhanced.SequenceStyleGenerator.class.getName()
: "seqhilo";
}
If you use the new identifier generators:
properties.put("hibernate.id.new_generator_mappings", "true");
The AUTO will actually use a SequenceStyleGenerator and where the database doesn't support sequences, you end up using a TABLE generator instead (which is a portable solution but it's less efficient than IDENTITY or SEQUENCE).
If you use the legacy identifier generators, you then end up with the "native" generation strategy, meaning:
public Class getNativeIdentifierGeneratorClass() {
if ( supportsIdentityColumns() ) {
return IdentityGenerator.class;
}
else if ( supportsSequences() ) {
return SequenceGenerator.class;
}
else {
return TableHiLoGenerator.class;
}
}
If a new Oracle12gDialect is going to be added and it will support IDENTITY, then AUTO might switch to IDENTITY rather than SEQUENCE, possibly breaking your current expectations. Currently there is no such dialect available so on Oracle you have SEQUENCE and in MSSQL you have IDENTITY.
Conclusion:
Try it like this:
#Id
#GenericGenerator(name = "native_generator", strategy = "native")
#GeneratedValue(generator = "native_generator")
private Long id;
make the id a Long instead of Integer, and you can let the HBMDDL handle the primary key column type.
force Hibernate to use the "native" generator
If your legacy system uses a table for generating sequence values and there was no hilo optimization ever used you can use a table identifier generator:
#Id
#GeneratedValue(generator = "table", strategy=GenerationType.TABLE)
#TableGenerator(name = "table", allocationSize = 1
)
private Long id;
You can also use the JPA table generator, just make sure you configure the right optimizer. For more info check my Hibernate tutorial
because
#GeneratedValue(strategy = GenerationType.AUTO)
use SequenceStyleGenerator by default in earlier versions
you have to look at this https://hibernate.atlassian.net/browse/HHH-11014

Problem with HSQLDB & SequenceGenerator

I have an entity which has an ID field:
#Id
#Column(name = "`U##ID_VOIE`")
#GeneratedValue(generator = "VOIE_SEQ")
private String id;
The class has the sequence generator defined as well:
#SequenceGenerator(name = "VOIE_SEQ", sequenceName = "VOIE_SEQ")
and the Oracle schema has the requisite sequence present. Everything works okay.
We also have tests, which uses an in-memory HSQLDB. Before running the tests, all the tables are created based on the Hibernate entity classes.
However the table for this particular class is not being created. And error pops up, because ID is a String and the SequenceGenerator in HSQLDB returns an INT / LONG / Numeric value.
The application is using a legacy Oracle database and ID_VOIE column must remain a String / Varchar.
Any solutions?
Using H2 instead.

Categories

Resources