Dealing with org.h2.jdbc.JdbcSQLException - grails

I am getting a org.h2.jdbc.JdbcSQLException error, I have an association whit a basic collection types
class User {
String email
String password
String role = "user"
String fullName
Boolean enabled = false
Date dateCreated
Date lastUpdated
static hasMany = [schools:String]
}
I create a view where user can select schools in checkboxs tag, then in a controller action I get schools values and try to apply next query in order to get all users that have some or all selected schools
def query = User.where {
schools in params.list("schools")
}
I get following error message
ERROR util.JDBCExceptionReporter - Parameter "#1" is not set; SQL statement:
select this_.id as id2_0_, this_.date_created as date2_2_0_, this_.email as email2_0_, this_.user_status as user4_2_0_, this_.full_name as full5_2_0_, this_.last_updated as last6_2_0_, this_.password as password2_0_, this_.user_role as user8_2_0_ from user this_ where this_.id in (?, ?) order by this_.date_created asc [90012-164]
thanks for your time

Related

Use INNER JOIN instead of LEFT JOIN when using gorm .Joins

I have the following structs:
type User struct {
ID uuid.UUID `gorm:"type:uuid"`
BirthDate *BirthDate `gorm:"<-"`
BirthDateID uuid.UUID
}
type BirthDate struct {
ID uuid.UUID `gorm:"type:uuid"`
Year int
Month int
Day int
}
(Those are make up structs). So basically there is a one to one relationship between user and birthdate, let's assume two users can't be born the same day.
I want to be able to retrieve all the users that were born in 2022, so then I have the following:
var result []*User
birthDateExample := BirthDate{Year:2022}
DB.Debug().Joins("BirthDate", s.Database.Select("id").Where(birthDateExample)).Preload(clause.Associations).Find(&result)
But it's making a left join query, so I am getting more results that I want:
SELECT `users`.`id`,`users`.`birth_date_id`,`BirthDate`.`id` AS `BirthDate__id`,`BirthDate`.`year` AS `BirthDate__year`,`BirthDate`.`month` AS `BirthDate__month`,`BirthDate`.`day` AS `BirthDate__day` FROM `reports` LEFT JOIN `birth_dates` `BirthDate` ON `users`.`birth_date_id` = `BirthDate`.`id` AND `BirthDate`.`year` = "2022"
How can I specify that I want a inner join? Because if I write the query as the following it works:
DB.Debug().Joins("JOIN birth_dates on birth_dates.id = users.billing_month_id and birth_dates.year = ?", 2022).Preload(clause.Associations).Find(&result)
But I would rather use the previous approach, Joins("BirthDates", query).

Grails 2.4.4 executeQuery() to join tables from a table of a database

this is the code for my domains.
class Btr {
Date dateBreak
int timeBreak
String typeBreak
User usuario
static constraints = {
}
static mapping = {
}
}
class User {
String name
String user
String password
String confirmPassword
String state
String extent
String movileNumber
String email
String address
Rol rol
static constraints = {
}
static mapping = {
}
}
This is the code for my controller.
def df = new SimpleDateFormat("yyyy-MM-dd HH:mm")
def startDate = params.startDate
def stopDate = params.stopDate
resultado = Btr .executeQuery("select dateBreak, timeBreak, typeBreak,
user, usuario.rol from Btr inner join User on user = usuario.rol where
dateBreak between :startDate" and :stopDate", [startDate:
df.parse(startDate), stopDate: df.parse(stopDate)])
render (view: "data", model: [result: resultado])
This is my view.
<g:each in="${result}" var="results" status="i">
<tr><td>{results.dateBreak}</td><td>{results.timeBreak}</td><td>
{results.typeBreak} </td><td>${results.usuario.rol}</td></tr>
</g:each>
Then i get this error when i submit the form.
in the GSP, when i am printing data,
Exception evaluating property 'dateBreak' for java.util.Arrays$ArrayList, Reason: groovy.lang.MissingPropertyException: No such property: dateBreak for class: java.sql.Timestamp
could someone please tell me how to join tables in grails with executeQuery and also would be nice to learn to do it with, withCriteria
resultado = Btr .executeQuery("select dateBreak, timeBreak, typeBreak,
user, usuario.rol from Btr inner join User on user = usuario.rol where
dateBreak between :startDate" and :stopDate", [startDate:
df.parse(startDate), stopDate: df.parse(stopDate)])
Should be
resultado = Btr .executeQuery("""select new map (btr.dateBreak as dateBreak, btr.timeBreak as timeBreak, btr.typeBreak as typeBreak,
u as user, user.usuario.rol as rol) from Btr btr join btr.user u where
btr.dateBreak between :startDate and :stopDate""", [startDate:
df.parse(startDate), stopDate: df.parse(stopDate)])
what you have is raw sql and not HQL which is a slight variation and uses actual domain objects to join
Use left join for hasMany where it may be null join for typical one to one relationship
Also use left join if one to one relationship can be null
Beyond that you could have put your actual query as a raw sql query like so
def sql=new Sql(dataSource)
return sql.rows(query,whereParams)

Mapping breaks my domain class

When I add the following mapping to my domain class, I get an error. Can someone help me see what I'm doing wrong here?
Domain Class
package sample
class Todo {
String name
String note
Date dateCreated
Date lastUpdated
Date dueDate
Date lastModifiedDate
Date completedDate
String priority
String status = "Started"
User owner
Category category
static belongsTo = [User, Category]
static constraints = {
name (blank:false)
priority()
status()
note (maxSize:1000, nullable:true)
completedDate(nullable:true)
dueDate(nullable:true)
}
String toString() {
name
}
}
Mapping I Want to Add
static mapping = {
table 'todo-tbl'
columns {
name column: 'name-str'
note column: 'note-str'
}
cache true
}
Error I Get When Adding Mapping
Error 500: Internal Server Error URI /sample/todo/list Class
org.h2.jdbc.JdbcSQLException Message Table "TODO" not found; SQL
statement: select this_.id as id72_0_, this_.version as version72_0_,
this_.category_id as category3_72_0_, this_.completed_date as
completed4_72_0_, this_.date_created as date5_72_0_, this_.due_date as
due6_72_0_, this_.last_modified_date as last7_72_0_,
this_.last_updated as last8_72_0_, this_.name-str as name9_72_0_,
this_.note-str as note10_72_0_, this_.owner_id as owner11_72_0_,
this_.priority as priority72_0_, this_.status as status72_0_ from
todo-tbl this_ limit ? [42102-164]
I solved this. Apparently using the hyphen in the table name was a big no-no. This stopped the table from being created in the DB.
Changed
table "todo-tbl"
to
table "todoTbl

How to ensure data integrity when using Table Per Subclass?

I am using the table per subclass strategy in Grails by setting the tablePerHierarchy property of the static mapping field in my superclass to false. This way, Grails creates one table for my superclass and one additional table for each of my subclasses.
However, while the superclass and subclass records share the same ID (primary key), there are no foreign key constraints to keep them consistent, i.e. it is possible to delete the superclass record, leaving the subclass record in an invalid state. I want to know if there is a setting/property to make GORM address this in some way, e.g. through constraints. Or is my only option to add foreign keys manually?
For example, given the following domain class as superclass:
class Product {
String productCode
static mapping = {
tablePerHierarchy false
}
}
And the following domain class as subclass:
class Book extends Product {
String isbn
}
This results in the creation of two tables, the Product table and the Book table. When creating a Book – through scaffolded pages, for instance – a record is inserted into each table, their only link being the fact that the ID value is the same for each. Specifically, the data might look like this:
PRODUCT
Id Version ProductCode
1 1 BLAH-02X1
BOOK
Id ISBN
1 123-4-56-7891011-1
Because there is no formal relationship defined at the database level for these tables, it is possible to delete one of the records and leave the other, which results in invalid data. Obviously I can use SQL to manually create a foreign key constraint on the two ID fields, but I was hoping to let Grails handle that. Is this possible?
Using Grails 2.2.1
Solved!
The following solution fixed this issue for me. Add the class below to src/java (this class cannot be written in Groovy)
package org.example;
import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration;
import org.hibernate.MappingException;
import org.hibernate.mapping.JoinedSubclass;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.RootClass;
import java.util.Iterator;
public class TablePerSubclassConfiguration extends GrailsAnnotationConfiguration {
private static final long serialVersionUID = 1;
private boolean alreadyProcessed = false;
#Override
protected void secondPassCompile() throws MappingException {
super.secondPassCompile();
if (alreadyProcessed) {
return;
}
for (PersistentClass persistentClass : classes.values()) {
if (persistentClass instanceof RootClass) {
RootClass rootClass = (RootClass) persistentClass;
if (rootClass.hasSubclasses()) {
Iterator subclasses = rootClass.getSubclassIterator();
while (subclasses.hasNext()) {
Object subclass = subclasses.next();
// This test ensures that foreign keys will only be created for subclasses that are
// mapped using "table per subclass"
if (subclass instanceof JoinedSubclass) {
JoinedSubclass joinedSubclass = (JoinedSubclass) subclass;
joinedSubclass.createForeignKey();
}
}
}
}
}
alreadyProcessed = true;
}
}
Then in DataSource.groovy set this as the configuration class
dataSource {
configClass = 'org.example.TablePerSubclassConfiguration'
pooled = true
driverClassName = "org.h2.Driver"
username = "sa"
password = ""
dbCreate = "update"
url = "jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000"
}
Update
I've submitted a pull request to Grails for this issue. The fix was included in Grails 2.3.8 or 2.3.9 (can't remember which).
Hibernate ensures the data integrity in case of table per subclass. In case of table per subclass, subclass maintains a primary key association with superclass. Have a look at Hibernate Table per subclass. To validate the fact here is your test case:
class Product {
String productCode
static mapping = {
tablePerHierarchy false
}
}
class Book extends Product{
String isbn
}
//Test Case
def testTablePerSubclass{
def product = new Product(productCode: 'XYZ456')
product.save(flush: true, failOnError: true)
def book = new Book(isbn: '123456123', productCode: 'ABC123')
book.save(flush: true, failOnError: true)
assert Book.list().size() == 1 //One Book
assert Book.list()*.id == [2] //Book id
assert Product.list().size() == 2 //One Product, one Book (2 Products)
assert Product.list()*.id == [1, 2] //Product id, Book Id
//Grab the product (book) to delete
def productToDelete = Product.get(book.id)
productToDelete.delete(flush: true)
assert Book.list().isEmpty() //Book deleted from Book table as well
assert Product.list().size() == 1 //One Product remaining in Product table
assert Product.list()*.id == [1] //Remaining Product Id
}
Keep logSql true in DataSource.groovy to see corresponding sqls getting executed.
Log Sql Output:-
Hibernate: insert into product (id, version, product_code) values (null, ?, ?)
Hibernate: insert into product (id, version, product_code) values (null, ?, ?)
Hibernate: insert into book (isbn, id) values (?, ?)
Hibernate: select this_.id as id0_0_, this_1_.version as version0_0_, this_1_.product_code as product3_0_0_, this_.isbn as isbn1_0_ from book this_ inner join product this_1_ on this_.id=this_1_.id
[com.example.Book : 2]
Hibernate: select this_.id as id0_0_, this_.version as version0_0_, this_.product_code as product3_0_0_, this_1_.isbn as isbn1_0_, case when this_1_.id is not null then 1 when this_.id is not null then 0 end as clazz_0_ from product this_ left outer join book this_1_ on this_.id=this_1_.id
[com.example.Product : 1, com.example.Book : 2]
Hibernate: delete from book where id=?
Hibernate: delete from product where id=? and version=?
Hibernate: select this_.id as id0_0_, this_1_.version as version0_0_, this_1_.product_code as product3_0_0_, this_.isbn as isbn1_0_ from book this_ inner join product this_1_ on this_.id=this_1_.id
[]
Hibernate: select this_.id as id0_0_, this_.version as version0_0_, this_.product_code as product3_0_0_, this_1_.isbn as isbn1_0_, case when this_1_.id is not null then 1 when this_.id is not null then 0 end as clazz_0_ from product this_ left outer join book this_1_ on this_.id=this_1_.id
[com.example.Product : 1]
Using Grails 2.2.2

GORM not saving record to association table from CONSOLE

class Pirate {
String name
static belongsTo = Ship
static hasMany = [ships: Ship]
}
class Ship {
String name
static hasMany = [crew: Pirate]
}
new Ship(name: "Ship1").addToCrew(new Pirate(name: "pirate1")).save()
The above code is only saving an entry in the Pirate and Ship table but not in the ship_crew table.
I'm aware of this technique used by Burt in the Spring Security Grails plugin but I'd still like to be able to use the hasMany and belongsTo
UPDATE
The above line of code seems to be saving the entries in all three: Pirate, Ship, and ship_crew table, however, from the console it only saves entries in the two tables and not in ship_crew
> new Ship(name: "Ship10").addToCrew(new Pirate(name: "pirate10")).save(failOnError:true)
new Ship(name: "Ship10").addToCrew(new Pirate(name: "pirate10")).save(failOnError:true)
Hibernate:
/* insert playwithgrails.Ship
*/ insert
into
ship
(version, name)
values
(?, ?)
Hibernate:
/* insert playwithgrails.Pirate
*/ insert
into
pirate
(version, name)
values
(?, ?)
===> playwithgrails.Ship : 29

Resources