Background:
I have upgraded my spring boot project from '2.5.12' to '3.0.0'.
As part of the upgrade hibernate was also updated to 6.1.5.
All the java entities are now using jakarta.persistence instead of javax.persistence
as required
The issue:
When the application starts an error is thrown
Schema-validation: missing table ...
The error is thrown from org.hibernate.tool.schema.internal.AbstractSchemaValidator
The function validateTable meant to validate that the entities match the DB tables.
#Override
protected void validateTables(
Metadata metadata,
DatabaseInformation databaseInformation,
ExecutionOptions options,
ContributableMatcher contributableInclusionFilter,
Dialect dialect, Namespace namespace) {
final NameSpaceTablesInformation tables = databaseInformation.getTablesInformation( namespace );
for ( Table table : namespace.getTables() ) {
if ( options.getSchemaFilter().includeTable( table )
&& table.isPhysicalTable()
&& contributableInclusionFilter.matches( table ) ) {
validateTable(
table,
tables.getTableInformation( table ),
metadata,
options,
dialect
);
}
}
}
Additional info:
The DB tables exist, i can log in and see them.
The databaseInformation.getTablesInformation( namespace ); returns empty results.
The namespace.getTables() shows all the tables correctly.
Hibernate generated classes are created O.K as part of the build (so annotations seem to be working).
Using MySQLDialect
Entities didn't change beside using jakarta.persistence
I don't get any "Connection refused " so connection to the DB is created.
The question:
Any idea what might be the cause?
Is there an issue with the model or reading schema data from the DB?
Might this be an issue of some dependency incompatibility?
Related
I need to use a SQL VIEW in a query using Room Persistence Library.
Using Commonsware's answer here I've been able to run a raw SQL statement to create the view during DB creation.
Room.databaseBuilder(context, MyDatabase.class, DB_NAME)
.addCallback(new RoomDatabase.Callback() {
#Override
public void onCreate(#NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
db.execSQL("CREATE VIEW view_name " +
"AS SELECT [...] "
);
}
})
.build();
The VIEW is actually created on the SQLite DB and works fine, but I cannot refer to the it in my Dao's #Query because I get a compile-time error:
Error:(100, 48) error: There is a problem with the query: [SQLITE_ERROR] SQL error or missing database (no such table: view_name)
Any idea on how to let Room to know about my view or to ignore the error?
UPDATE 17/12/2018
Version 2.1.0 and higher of the Room persistence library now provides support for SQLite database views:
https://developer.android.com/training/data-storage/room/creating-views
(see D-D's comment)
UPDATE 15/12/2017
Be aware that this solution actually breaks DB migrations.
Problem is with the Entity primary key that obviously doesn't exist on the view, so migration is not valid.
See CommonsWare's comment for a possible hacky workaround.
ORIGINAL ANSWER
It seems that this is not possible at the moment using Room.
Anyway I've done it using a workaround: I've created an Entity with the same name and columns as the view (only the name is actually mandatory), this will create a table on DB and allow you to use that table name in queries without compile-time errors.
Then during Room DB creation I DROP this entity's table just before the CREATE VIEW.
Room
.databaseBuilder(context, DueDatabase.class, DB_NAME)
.addCallback(new RoomDatabase.Callback() {
#Override
public void onCreate(#NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
//Drop the fake table and create a view with the same name
db.execSQL("DROP TABLE view_name");
db.execSQL("CREATE VIEW view_name " +
"AS SELECT [...]"
);
}
})
.build();
I'm using grails 3.02 and all was fine, but since I moved several domain classes from another grails project I started seeing this error when I do start integration tests:
grails.validation.exceptions.ConstraintException: Exception thrown applying constraint [unique] to class [class com.mypackage.Individual] for value [true]: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#6397593b has not been refreshed yet
The domain class code:
class Individual {
String institutionId
String email
static mapping = {
table 'db.individual'
id generator: 'sequence', params: [sequence: 'db.individual_id_sequence']
institutionId index: 'db.individual_institution_id_idx'
email index: 'db.individual_email_idx'
}
static constraints = {
institutionId(blank: false)
email(unique: true)
}
}
The strange thing is: this code is working in another project but does not want to work in this one, in where I moved it to. I compared configs(application.yml and application.groovy and build.gradle) - but all is basically the same.
Any help, grails gurus?
I think I have found why I had this exception. It was not related to constrains at all.
I just had some other fields in my domain class which used to be calculated, so it was unmapped field. But grails used to try to map this field into a real database column. Once I've defined my own getter(in which the field initializes) for this calculated field all became fine.
But the grails exception btw is stupid and disorienting - it does not describe the root cause at all.
I'd like to use a 128-bit UUID rather than Long for the id field on all of my Grails domains. I'd rather not have to specify all of the mapping information on every domain. Is there a simple way to achieve this in a generic/global way? I'm using Grails 2.3.x, the Hibernate 3.6.10.2 plugin, the Database Migration Plugin 1.3.8, and Oracle 11g (11.2.0.2.0).
There seem to be a number of questions related to this, but none provide complete, accurate, and up-to-date answers that actually work.
Related Questions
What's the best way to define custom id generation as default in Grails?
grails using uuid as id and mapping to to binary column
Configuring Grails/Hibernate/Postgres for UUID
Problems mapping UUID in JPA/hibernate
Custom 16 digit ID Generator in Grails Domain
Using UUID and RAW(16)
If you want to use a UUID in your Grails domain and a RAW(16) in your database, you'll need to add the following.
For every domain, specify the id field. Here's an example using ExampleDomain.groovy
class ExampleDomain {
UUID id
}
Add the following mapping to Config.groovy
grails.gorm.default.mapping = {
id(generator: "uuid2", type: "uuid-binary", length: 16)
}
For details on the three values I've selected, please see these links.
http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/mapping.html#d0e5294
http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/types.html#types-basic-value-uuid
How should I store a GUID in Oracle?
Add a custom dialect to your data source entry in Datasource.groovy. If you are using Hibernate 4.0.0.CR5 or higher, you can skip this step.
dataSource {
// Other configuration values removed for brevity
dialect = com.example.hibernate.dialect.BinaryAwareOracle10gDialect
}
Implement the custom dialect you referenced in step #3. Here is BinaryAwareOracle10gDialect implemented in Java. If you are using Hibernate 4.0.0.CR5 or higher, you can skip this step.
package com.example.hibernate.dialect;
import java.sql.Types;
import org.hibernate.dialect.Oracle10gDialect;
public class BinaryAwareOracle10gDialect extends Oracle10gDialect {
#Override
protected void registerLargeObjectTypeMappings() {
super.registerLargeObjectTypeMappings();
registerColumnType(Types.BINARY, 2000, "raw($l)");
registerColumnType(Types.BINARY, "long raw");
}
}
For more information about this change, please see the related Hibernate defect https://hibernate.atlassian.net/browse/HHH-6188.
Using UUID and VARCHAR2(36)
If you want to use a UUID in your Grails domain and a VARCHAR2(36) in your database, you'll need to add the following.
For every domain, specify the id field. Here's an example using ExampleDomain.groovy.
class ExampleDomain {
UUID id
}
Add the following mapping to Config.groovy
grails.gorm.default.mapping = {
id(generator: "uuid2", type: "uuid-char", length: 36)
}
For details on the three values, please see the links in step #2 from the previous section.
I think there is a easy way:
String id = UUID.randomUUID().toString()
static mapping = {
id generator:'assigned'
}
I have created a simple JAVA app to learn database connection.
I have table USR_BOOKS in Oracle 11g database. Using EclipseLink(JPA 2.0) Persistence libray.
Using "Create Entity From Database", I created a class in Java, and created JPA Controller class.
Everything seems to work fine except that I always get
[EL Warning]: 2012-10-30 16:50:31.957--ServerSession(1278203495)--Exception
[EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLSyntaxErrorException: ORA-00955: name is already used by an existing object
Error Code: 955
Call: CREATE TABLE USR_BOOKS (ID NUMBER(19) NOT NULL, NAZOV VARCHAR2(255) NULL, PRIMARY KEY (ID))
Query: DataModifyQuery(sql="CREATE TABLE USR_BOOKS (ID NUMBER(19) NOT NULL, NAZOV VARCHAR2(255) NULL, PRIMARY KEY (ID))")
I am not calling the CREATE TABLE query anywhere, but until I call function
EntityManager em = emf.createEntityManager();
the error is not there
It looks like that the function createEntityManager() creates the SQL statement and sends it into database.
I tried deleting the table from database. Then the program creates the table USR_BOOKS in database - again, I am NOT accidentally calling any function that could cause it.
This is basically my code:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("JavaOracleDBPU2");
EntityManager em = emf.createEntityManager();
UsrBooksJpaController booksController = new UsrBooksJpaController(emf);
List<UsrBooks> usrBooksAll = booksController.findUsrBooksEntities();
System.out.println(usrBooksAll);
the code works, even prints data from the table, just getting the error
Possibly in persistence.xml eclipselink.ddl-generation property does have value create-tables. Try none instead:
<property name="eclipselink.ddl-generation" value="none"/>
I am integrated with a legacy Oracle database which uses assigned VARCHAR2 values for primary keys. I am creating a one-to-many relationship with this existing table. The legacy table is called Applications (which I may not alter) and the new table is called Projects. Many projects may be assigned to one application.
When GORM creates the Project table it is creating a NUMBER column for the foreign key, application_id, even though this is a VARCHAR2 field in the Applications table.
class Application {
static hasMany = [projects : Project]; // does not fix problem
String application_id;
...
static mapping = {
table 'applications'
version false
id (column:'application_id')
}
static constraints = {
application_id(maxSize:16,blank:false,unique:true,type:"string",generator:"assigned")
}
...
}
class Project {
Application application;
...
}
When I compile the app I get warnings like this:
Unsuccessful: alter table project add constraint FKED904B1956694CB5 foreign key (application_id)
ORA-02267: column type incompatible with referenced column type
When I run the app and click on Application controller I get this error:
SQL state [99999]; error code [17059]; Fail to convert to internal representation; nested exception is java.sql.SQLException: Fail to convert to internal representation
When I click on Project | create I get this error:
Fail to convert to internal representation; nested exception is java.sql.SQLException: Fail to convert to internal representation at /project/create:172
So how can I set the Project class to expect a VARCHAR2 foreign key for the Application?
Thanks for any help!
Look at this site. Maybe it will help you.
Here is the correction in the Application class... in case anyone else searches for this:
class Application {
static hasMany = [projects : Project];
String application_id;
String id // <--- part of solution
static mapping = {
id column:'application_id',generator:'assigned' // <--- part of solution
}
static constraints = {
application_id(maxSize:16,blank:false,unique:true) // <--- part of solution
columns { // <--- part of solution
id type:'text'
application_id type:'text'
}
}