Unit testing Hibernate with multiple database catalogs - java

I have an issue testing a Hibernate application which queries multiple catalogs/schemas.
The production database is Sybase and in addition to entities mapped to the default catalog/schema there are two entities mapped as below. There are therefore three catalogs in total.
#Table(catalog = "corp_ref_db", schema = "dbo", name = "WORKFORCE_V2")
public class EmployeeRecord implements Serializable {
}
#Table(catalog = "reference", schema = "dbo", name="cntry")
public class Country implements Serializable {
}
This all works in the application without any issues. However when unit testing my usual strategy is to use HSQL with hibernate's ddl flag set to auto and have dbunit populate the tables.
This all works fine when the tables are all in the same schema.
However, since adding these additional tables, testing is broken as the DDL will not run as HSQL only supports one catalog.
create table corp_ref_db.dbo.WORKFORCE_V2
user lacks privilege or object not found: CORP_REF_DB
If there were only two catalogs then I think it would maybe be possible to get round this by changing the default catalog and schema in the HSQL database to that one explicitly defined:
Is there any other in-memory database for which this might work or is there any strategy for getting the tests to run in HSQL.
I had thought of providing an orm.xml file which specified the default catalog and schema (overiding any annotations and having all the defined tables created in the default catalog/schema) however these overrides do not seem to be observed when the DDL is executed i.e. I get the same error as above.
Essentially, then I would like to run my existing tests and either somehow have the tables created as they are defined in the mappings or somehow override the catalog/schema definitions at the entity level.
I cannot think of any way to achieve either outcome. Any ideas?

I believe H2 supports catalogs. I haven't used them in it myself, but there's a CATALOGS table in the Information Schema.

I managed to achieve something like this in H2 via IGNORE_CATALOGS property and version 1.4.200
However, the url example from their docs did not seem to work for me, so I added a statement in my schema.xml:
SET IGNORE_CATALOGS = true;

Related

spring.datasource.url how to create multiple enum/domain before hibernate is scanning the entities

I have spring boot application with pgsql as db. I am writing test cases for the api's and for the test cases i am using h2 db. I have multiple entities where i have multiple enums. For the test cases we have
spring.jpa.hibernate.ddl-auto = create-drop
When hibernate is creating the tables from entity it is giving Unknown data type: "enum_type1".
I took a reference from this question:
How to fake ENUM columns in the H2 database for play unit testing?
So i updated my property as follows:
spring.datasource.url= jdbc:h2:mem:test;MODE=PostgreSQL;INIT=CREATE DOMAIN IF NOT EXISTS enum_type1 as VARCHAR(255),CREATE DOMAIN IF NOT EXISTS enum_type2 as VARCHAR(255);DB_CLOSE_ON_EXIT=FALSE
But it is giving following error:
org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "CREATE DOMAIN IF NOT EXISTS enum_type1 AS VARCHAR(255),[*]CREATE DOMAIN IF NOT EXISTS enum_type2 AS VARCHAR(255)"; SQL statement:
So how can we create multiple enum/domain before hibernate is scanning the entities?
Any help will be appreciated, Thanks.
You can't use a comma as a separator between statements. If you want to specify multiple statements in INIT parameter, they should be separated with \;. Note that INIT=something parameter should be separated from other parameters, such as DB_CLOSE_ON_EXIT with ; (without the \).
jdbc:h2:mem:test;MODE=PostgreSQL;INIT=CREATE DOMAIN IF NOT EXISTS enum_type1 as VARCHAR(255)\;CREATE DOMAIN IF NOT EXISTS enum_type2 as VARCHAR(255);DB_CLOSE_ON_EXIT=FALSE
H2 also has a built-in ENUM data type, it should be better to use it instead of VARCHAR.
PostgreSQL compatibility mode should be normally used with DATABASE_TO_LOWER=TRUE.
And the whole idea to use different DBMS for tests and production doesn't look good. Normally you should use multiple DBMS only when your application is initially designed to work with them all.

Moving auditing table with java envers to new database instance

I have a Mysql DB, schema name "myschema". This schema has tables, where some of this tables are
audit tables. This is my dependency on my java project.
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-envers</artifactId>
<version>5.1.0.Final</version>
</dependency>
Now I had like to remore this audit tables on my currect DB and more them on a separate instance, with a branch new uri.
How can this be done? Any advise, thank you in advance
Please take a look at the Configuration Options:
org.hibernate.envers.default_schema
The default schema name that should be used for audit tables.
org.hibernate.envers.default_catalog
The default catalog name that should be used for audit tables.
The option that you should use depends on if your database.
There is also a bug that if you use the default revision entity mappings provided out of the box by Envers that those mappings won't be properly mapped when using these configuration options, only the tables that are related to the entity mappings.
In order to properly map the REVINFO table to the appropriate schema or catalog, a custom revision entity mapping will need to be used in cojunction with a the #Table annotation in order to explicitly specify the schema/catalog. Please see the section Revision Log that describes using a custom #RevisionEntity annotated entity mapping with Envers.
AFAIK Envers does not support using a separate database/DataSource. There seem to be a couple of ways to get the data to the other database: Oracle Database Link - MySQL Equivalent?
Alternatively I guess you could write a custom DataSource that delegates statements to different datasources depending on the statement.
Check if an auditing table is mentioned and if so send it to the audit database.

With DataJpaTest Repository Tests using MySQL, Hibernate doesn't set User to auto-increment in H2 DB

I'm trying to test my Spring Boot repositories using DataJpaTest. I'm using MySQL, so all of my models are using IDENTITY for id generation:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
But as you can see from the screenshot below, when I run my tests, Hibernate sets "generated by default as identity" for the ids of all of my models except for User and Property:
This makes it so that I cannot create users (or properties) in my tests, since GenerationType.IDENTITY sets always sets the id to null before sending it to the db, which results in the following error:
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
Does anyone know why this is happening? And, of course, more important than the why is what can I do to fix it? :)
Update
To simplify the problem a bit and provide different errors for different things I've tried...
My DataJpaTests are using H2, which I guess is automagically generating the db structure from the code. My real DB is MYSQL, which is generated in a separate project.
Scenario 1:
When I set GenerationType to IDENTITY, the live DB works, but the test DB gives me could not execute statement; SQL [n/a]; constraint [null].
Scenario 2:
When I set GenerationType to AUTO, the test DB works, but the live DB gives me Table 'tablename.hibernate_sequence' doesn't exist.
Scenario 3:
Trying to make MYSQL work with GenerationType AUTO. I have found nothing in quite a lot of searching on how to tell Hibernate to default MYSQL to identity instead of table. I've found rather a lot saying to never use table and that overriding this is impossible without changing the Hibernate source code. This is a bunch of BS that makes me wonder what the Hibernate developers are smoking.
Scenario 4:
Trying to make H2 work with GenerationType IDENTITY. I've had some luck here with the following:
Putting spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MODE=MYSQL in a test.properties file.
Annotating my Test class with #TestPropertySource(locations= "classpath:test.properties") and #AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
This gets rid of the null constraint error, but instead I'm now getting The database returned no natively generated identity value. Presumably, this is because, while the actual SQL code had auto_increment for the id, whatever magic is being used to generate the table for H2 isn't getting it there.
Addendum: The thing that is really frustrating about all of this is that it works totally fine for most of the tables. Out of the more than 20 tables in my DB, all but two of them auto generate and increment their ids just fine using IDENTITY. It makes no sense at all that some of them would work and some of them wouldn't.
The problem was another model with #Table(name = "user") as an annotation. That model also had the Id column defined, but without a generated value. With the conflict, Hibernate chose that one to define the id.
MySql works better with
#GeneratedValue(strategy = GenerationType.AUTO)
its also better because it produces auto-increment primary key in most RDBMS

Spring Boot application doesn't create schemas for JPA #Table annotation

I want to have tables located in different database schemas. But unfortunately, I can't achieve this with Spring Boot. Here steps to reproduce it.
Create a new Spring Boot project on http://start.spring.io version 2.0.5 (with derby and PostgreSQL dependencies)
Create simple entity
#Entity
#Table(name = "my_table")
public class MyTable {
#Id Integer id;
}
Add only next property to the application.properties with value 'update' or 'create' (if you try 'create-drop' then you get another error described here: https://github.com/spring-projects/spring-boot/issues/7706#issuecomment-268798059). Now Derby datasource will be used by default.
spring.jpa.hibernate.ddl-auto=create
Run a generated test or main class. Be sure all works fine.
Modify the entity, add attribute schema to the #Table annotation. Now the entity looks like:
#Entity
#Table(name = "my_table", schema = "my_schema")
public class MyTable {
#Id Integer id;
}
Run a test (or main class). This time I get an error while Spring Boot initialization process "java.sql.SQLSyntaxErrorException: Schema 'MY_SCHEMA' does not exist":
Full log listing is available here: https://gist.github.com/asaushkin/8d767c92b2e7025dd359f7be43eefdd6
Check on PostgreSQL. This error reproduces on a PostgreSQL instance too. Without the 'schema' attribute Spring Boot app runs perfect, but as soon as this attribute appears on the #Table annotation the exceptions are thrown.
Full log is here: https://gist.github.com/asaushkin/dd0d677964556bf943c4f013d4785372
My question is: why are schemas not created by Spring Boot?
These options can't resolve this issue too:
spring.jpa.properties.javax.persistence.schema-generation.create-database-schemas=true
spring.jpa.properties.hibernate.hbm2dll.create_namespaces=true
Links
https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#configurations-hbmddl
https://docs.spring.io/spring-boot/docs/current/reference/html/howto-data-access.html#howto-configure-jpa-properties
Update (11 March 2019):
I've just check the current behavior of the issue. I wonder, but currently with Derby driver all works fine and the table is created with the specified schema. But in PostgreSQL an error continues exists.
Generated SQL (for PostgreSQL) is:
create table my_schema.my_table (id int4 not null, primary key (id))
Check that are you specifying the database dialect in the application.properties file or not for more check this thread.
Unable to get spring boot to automatically create database schema
I had the same problem with PostgreSQL and JPA (ERROR o.h.e.jdbc.spi.SqlExceptionHelper - ERROR: relation "schema.table" does not exist) and I figured out this solution.
In your entities classes, add escape characters \", between database element´s name. For instance:
Use this form:
#Table(name = "\"USUARIO\"", schema="\"INVENTARIODB\"")
Rather than a typical way
#Table(name = "USUARIO", schema="INVENTARIODB")
The same applies for columns names
#Column(name = "\"ID\"", nullable = false, updatable = false)
private Long id;
Rather than
#Column(name = "ID", nullable = false, updatable = false)
private Long id;
UPDATE:
I discovered the reason that was causing the problem. I used Valentina Studio to create my DB, if I use capital letters (MYTABLE), instead lower-case letters (mytable) to create my tables, I had to use double quotes inside SQL statements. This is because PostgreSQL is case sensitive. If you can´t change your database then use my last solution. Also is a good idea to enable spring.jpa.show-sql=true property, so you can see hibernate´s queries and know what´s going on.
Rename spring.jpa.properties.javax.persistence.schema-generation.create-database-schemas to spring.jpa.properties.javax.persistence.create-database-schemas. In other words, remove '.schema-generation'.
I just had the same problem not with PostgreSQL but H2 - schemas weren't being created. But, as I've discovered, the problem is not with H2 (or, likely, PostgreSQL) but, rather, Hibernate (it deviates from the standard, regarding that nomenclature). That likely means that this solution will work for you too.

How to tell Hibernate annotation #Column to be case-sensitive?

I'm trying to do a simple SELECT query in a table named ECM (in uppercase) on a Sybase db with Hibernate. I've annotated my DBO this way :
#Entity
#Table(name="ECM")
public class RelationshipDbo {
...
}
However, I'm facing a "table not found" error : the generated SQL has the table name in lowercase. I cannot change the database configuration to tell it to be case-insensitive.
I've also tried putting quotes like this :
#Table(name="`ECM`")
and this :
#Table(name="'ECM'")
Result : the quotes are added in the query, but the table name is still converted from uppercase to lowercase.
Technical information :
Hibernate 4.3
JPA 1.2
org.hibernate.dialect.SybaseDialect
Have you guys any idea?
EDIT: Also tried this Hibernate changes #Table(name) to lowercase
Then my columns names and table name are automatically quoted, but the names still get lowercased.
I think I have your answer:
Basically, you need to change the naming strategy for you JPA provider. How you do this will depend on how you setup your project.
In my case, using spring boot data I set a property in my application.properties to
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.EJB3NamingStrategy
Without more details from you I can't give more specifics on how to do this.
My goal is a little different since was trying to create tables upper case and hibernate created them in lower case. Also i was using MySQL not Sybase.
But for me quoting the names like this worked:
#Entity
#Table(name="\"ECM\"")
public class RelationshipDbo {
...
}
Then tables were created upper case. Maybe that helps also for the queries.
What is your Sybase db version ?
SybaseDialect has been deprecated in Hibernate 3.5 and then refactored since Hibernate 4.1 with a bunch of subclasses matching different versions of Sybase. Have you tried one of the subclasses to see if it makes any difference?
org.hibernate.dialect.Sybase11Dialect
org.hibernate.dialect.SybaseAnywhereDialect
org.hibernate.dialect.SybaseASE15Dialect
Try this:
Use backticks as in #Table(name="`ECM`")?
This must work from Hibernate point. If not then problem should be in DB (if i'm not wrong)

Categories