How to use hibernate.default_schema and hibernate.default_catalog - mysql

I am using Mysql and earlier in my hibernate configuration file I mentioned
<property name="hibernate.connection.url">jdbc:mysql://localhost/TestDB</property>
as the connection url where TestDB is the schema I am connecting to.
I want to specify the default schema in configuration file as
<property name="hibernate.connection.url">jdbc:mysql://localhost</property>
<property name="hibernate.default_schema">TestDB</property>
but it is not working in this way and It gives me an error saying that
java.sql.SQLException: No database selected
Can anyone help me with an example of how to use hibernate.default_schema , hibernate.default_catalog in hibernate configuration file?

You should use hibernate.default_catalog instead of hibernate.default_schema.
According to the MySql documentation the connection url should have the following format:
protocol//[hosts][/database][?properties]
where
database
The default database or catalog to open. If the database is not specified, the connection is made with no default database. In this case, either call the setCatalog() method on the Connection instance, or specify table names using the database name (that is, SELECT dbname.tablename.colname FROM dbname.tablename...) in your SQL statements. Opening a connection without specifying the database to use is, in general, only useful when building tools that work with multiple databases, such as GUI database managers.
Imagine we have the following MySql databases:
create database DB_A;
create database DB_B;
create table DB_A.TST_EMPLOYEE(
emp_id int primary key,
emp_name varchar(100)
);
create table DB_B.TST_EMPLOYEE(
emp_id int primary key,
emp_name varchar(100)
);
then we can specify the database connection in the hibernate.cfg.xml in the following way:
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306</property>
<property name="hibernate.default_catalog">DB_A</property>
<property name="hibernate.connection.username">your_user</property>
<property name="hibernate.connection.password">your_pass</property>
declare entities for DB_A.TST_EMPLOYEE and DB_B.TST_EMPLOYEE tables in the following way:
#Entity
#Table(name = "TST_EMPLOYEE")
public class EmployeeA
{
// ...
}
#Entity
#Table(name = "TST_EMPLOYEE", catalog = "DB_B")
public class EmployeeB
{
// ...
}
and then use them in the usual way. Also for the native queries you can use the {h-catalog} placeholder for the default catalog specified in the hibernate.default_catalog property.
P.S. I have to say that the catalog and schema notions can have quite different meaning from database to database. See this for the reference.

Related

JPA Hibernate - Multiple Database Dialects and nvarchar(length) data type

I have to do a project using JPA + Hibernate in which I'm using 3 dialects: MySQL5InnoDBDialect, MSSQL2012Dialect and Oracle12cDialect.
Right now I have a specification which is telling me that for some column from:
Oracle database, I have to use NVARCHAR2(LENGTH) data type
MySql database, I have to use VARCHAR(LENGTH) data type
MSSQL database, I have to use NVARCHAR(LENGTH) data type
... and here is my problem..
If I use:
#Column(name="columnName" length = 255)
private String columnName;
hibernate generates varchar(255) and this is good just for MySQL
If I use:
#Column(name="columnName", columnDefinition="nvarchar2(255)")
private String columnName;
it's not possible in MySQL, i get error because of columnDefinition, but in oracle is okay
I tried to customize MySQL dialect creating
public class CustomMySQL5InnoDBDialect extends MySQL5InnoDBDialect{
public CustomMySQL5InnoDBDialect() {
super();
registerColumnType(Types.NVARCHAR, "nvarchar2($l)");//$l not $1
registerHibernateType(Types.NVARCHAR, StandardBasicTypes.STRING.getName());
}
}
and giving this class in hibernate configuration for MySQL dialect.
I have the same problem in MySQL if I'm using columnDefinition property.
Can you help with this problem please?
The solution is to make use of the feature that the JPA API spec provides you with for just this situation. Define a file orm.xml for each datastore that you need to support, and enable the requisite one when using each database. See this link for details of the file format. That way you don't need to think about hacking the internal features of whichever JPA provider you are using, and you also retain JPA provider portability, as well as database portability
The idea of putting schema specific information info (static) Java annotations is an odd one, even more so when wanting database portability.

jooq specify database runtime

I have the exact same database definition for multiple databases ( and database servers ). How do I tell Jooq to use the same database as the "Connection" I created to connect to the DB?
Example ( for MySQL ):
jdbc:mysql://localhost:3306/tsm - my development DB ( tsm ), used to generate code
jdbc:mysql://RemoteAmazonDBHost:3306/customer1 - one of my customers
jdbc:mysql://RemoteAmazonDBHost:3306/customer2 - Another customer
All 3 databases have the same definition, the same tables, indexes, etc. The TSM one is the standard our application uses.
Maybe I should be using DSL.using( Connection, Setting ) instead of DSL.using(Connection)? Is that what the manual is implying here?
If I only have one "Input" schema, do I have to specify it? In other words, can I do something like this:
Settings settings = new Settings()
.withRenderMapping(new RenderMapping()
.withSchemata(
new MappedSchema().withOutput(
databaseInfo.getProperties().getProperty("database.db"))));
Or do I have to do something like this:
Settings settings = new Settings()
.withRenderMapping(new RenderMapping()
.withSchemata(
new MappedSchema().withInput("TSM")
.withOutput(databaseInfo.getProperties().getProperty("database.db"))));
I'm assuming you're using code generation. In that case, it might be the easiest to not generate the schema at all but use <outputSchemaToDefault> in the code generation configuration, e.g.
<configuration>
<generator>
<database>
<inputSchema>your_codegen_input_schema_here</inputSchema>
<outputSchemaToDefault>true</outputSchemaToDefault>
</database>
</generator>
</configuration>
See the manual for details: https://www.jooq.org/doc/latest/manual/code-generation/codegen-advanced/codegen-config-database/codegen-database-catalog-and-schema-mapping/
If you want to keep your generated code with schema qualification and map things at runtime, then your second attempt seems correct. Pass this to your Configuration (i.e. the DSL.using() call):
Settings settings = new Settings()
.withRenderMapping(new RenderMapping()
.withSchemata(new MappedSchema()
.withInput("TSM")
.withOutput(databaseInfo.getProperties().getProperty("database.db"))));
More details can be found here: https://www.jooq.org/doc/latest/manual/sql-building/dsl-context/custom-settings/settings-render-mapping

Schema name in Create index statement while generating datanucleus JDO schema

I am trying to generate schema from the DataNucleus SchemaTool for a mysql database, that will store countries and states. Here is a sample of that code:
#PersistenceCapable
Public class State{
private String shortCode;
private String fullName;
#Column(allowsNull = "true",name="country_id")
private Country countryId;
}
The following are my schemaGeneration properties:
datanucleus.ConnectionDriverName=com.mysql.jdbc.Driver
datanucleus.ConnectionURL=jdbc:mysql://localhost:3306/geog
datanucleus.ConnectionUserName=geog
datanucleus.ConnectionPassword=geogPass
datanucleus.schema.validateTables=true
datanucleus.mapping.Catalog=geog
datanucleus.mapping.Schema=geog
In my Country class as well, I have a mapping from a Collection, so that the FK reference for States to the Country table is built correctly.
But there is one problem. In the SQL script generated, the Index part has the Schema name as part of the index name itself, which fails the entire script. Here is that piece:
CREATE INDEX `GEOG`.`MST_STATE_N49` ON `GEOG`.`MST_STATE` (`COUNTRY_ID`);
Notice the schema name in the GEOG.MST_STATE_N49 part of the index' name.
I tried setting the schema and catalog name to blank but that yields a ''.MST_STATE_N49 which still fails.
I am using MySQL Server 5.7.17 using the 5.1.42 version of the JDBC driver (yes, not the latest) on Data nucleus JDO 3.1
Any hints on how I can get rid of the schema/catalog name in the generated DDL?
Why are you putting "datanucleus.mapping.Schema" when using MySQL ? MySQL doesnt use schema last I looked. Similarly the "datanucleus.mapping.Catalog" is effectively defined by your URL! MySQL only actually supports JDBC catalog, mapping on to "database", as per this post. Since DataNucleus simply uses the JDBC driver then catalog is the only useful input.
Consequently removal of both schema and catalog properties will DEFAULT to the right place.
After the comment above from Neil Stockton, I commented out both the properties and it worked. Effectively, this is what is needed:
datanucleus.ConnectionDriverName=com.mysql.jdbc.Driver
datanucleus.ConnectionURL=jdbc:mysql://localhost:3306/geog
datanucleus.ConnectionUserName=geog
datanucleus.ConnectionPassword=geogPass
datanucleus.schema.validateTables=true
Hopefully, I can get the answer to the other question (Pt. 2 in my reply-comment above) as well.

Table 'xxx.__MigrationHistory' doesn't exist error when running update-Database in Entity Framework for MySql database

Currently I have an application which uses Entity Framework 6.1.3 along with Sql Server 2012. I use Code first migration approach for my DB. In Sql Server DB, I have created tables with schema name as table prefix, such as TestDB.TestSchema.tblXyz where TestDB is my database and TestSchema is my schema name.
Now I want to change my application to use MySql database and to follow the same convention for table name and schema.
I overrided the onModelCreating method of HistoryContext class to add a prefix to tables as following ,
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema("TestSchema");
modelBuilder.Entity<HistoryRow>().Property(h => h.MigrationId).HasMaxLength(128).IsRequired();
modelBuilder.Entity<HistoryRow>().Property(h => h.ContextKey).HasMaxLength(200).IsRequired();
}
But when I ran update-database -verbose command in the package manager console, it gave the error
"Table 'TestDB.__MigrationHistory' doesn't exist".
Below is the a part of the script generated while running migration :
create table `TestSchema.__MigrationHistory` (`MigrationId` varchar(128)
not null ,`ContextKey` varchar(200) not null ,`Model` longblob
not null,`ProductVersion` varchar(32) not null ,primary key (
`MigrationId`,`ContextKey`) ) engine=InnoDb auto_increment=0
INSERT INTO `__MigrationHistory`( ...
As you can see while inserting into __MigrationHistory table, it is not prefixing the schema name to that. So it is resulting in the above error.
Do anybody else have faced the same issue? What can be done here to make Entity Framework pick the right table name?
Thanks...
You must to remove this row:
modelBuilder.HasDefaultSchema("TestSchema");
Then EF stops to add schema prefix to each table name.
Tables will be created in tablespace specified in connection string (parameter "Initial Catalog=..." is app.config).

Turning IDENTITY_INSERT ON on a table to load it with DB Unit

I try to load a table, that have an identity column, with DB Unit. I want to be able to set the id value myself (I don't want the database generate it for me).
Here is a minimal definition of my table
create table X (
id numeric(10,0) IDENTITY PRIMARY KEY NOT NULL
)
To insert a line in X, I execute the following SQL
set INDENTITY_INSERT X ON
insert into X(id) VALUES(666)
No problem. But when I try to load this table with the following db unit XML dataset (RS_7_10_minimal_ini.xml)
<dataset>
<X id="666"/>
</dataset>
using the following minimal JUnit (DBTestCase) test case :
package lms.lp.functionnal_config;
import java.io.FileInputStream;
import org.dbunit.DBTestCase;
import org.dbunit.PropertiesBasedJdbcDatabaseTester;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;
import lms.DBUnitConfig;
import org.junit.Test;
public class SampleTest extends DBTestCase
{
public SampleTest(String name)
{
super( name );
System.setProperty( PropertiesBasedJdbcDatabaseTester.DBUNIT_DRIVER_CLASS, DBUnitConfig.DBUNIT_DRIVER_CLASS );
System.setProperty( PropertiesBasedJdbcDatabaseTester.DBUNIT_CONNECTION_URL, DBUnitConfig.DBUNIT_CONNECTION_URL );
System.setProperty( PropertiesBasedJdbcDatabaseTester.DBUNIT_USERNAME, DBUnitConfig.DBUNIT_USERNAME );
System.setProperty( PropertiesBasedJdbcDatabaseTester.DBUNIT_PASSWORD, DBUnitConfig.DBUNIT_PASSWORD );
}
protected IDataSet getDataSet() throws Exception
{
return new FlatXmlDataSetBuilder().build(new FileInputStream("src/test/resources/RS_7_10_minimal_ini.xml"));
}
#Test
public void testXXX() {
// ...
}
}
It fails with the following exception
com.sybase.jdbc3.jdbc.SybSQLException: Explicit value specified for identity field in table 'X' when 'SET IDENTITY_INSERT' is OFF.
It seems DB Unit does not turn identity ON before inserting a row for which the value of the identity column is specified.
I already tried to execute myself on the connection retrieved from the JdbcDataBaseTester but no luck. Probably a new connection or not the same connection used to push the data into de DB.
Any idea?
Thanks a lot for your help all !
Octave
Yes, found the solution in the DBUnit FAQ actually
Can I use DbUnit with IDENTITY or auto-increment columns?
Many RDBMSes allow IDENTITY and auto-increment columns to be implicitly overwritten with client values. DbUnit can be used with these RDBMS natively. Some databases, like MS SQL Server and Sybase, need to explicitly activate client values writing. The way to activate this feature is vendor-specific.
DbUnit provides this functionality for MS SQL Server with the InsertIdentityOperation class.
Although it is written for the MS SQL Server, is also works for Sybase. So I push my data set to db with
new InsertIndentityOperation(DatabaseOperation.CLEAN_INSERT).execute(connection,initialDataSet);
Et voilĂ .
Thanks for your answer rawheiser.
Not familar enough with DBUnit to help you with the specifics; but I have used a table truncate and reseeding the identity value in similar situations.
dbcc checkident