In a Grails/GORM app, can I rename the implicit domain id column to entity_id and auto-increment using an existing sequence?
class Practitioner {
Long entityId
String providerName
static mapping = {
id name: 'entityId', column: 'entity_id', generator:'sequence', params:[sequence:'hibernate_sequence']
}
}
Attempting to save in console fails, (and yes, sequence exists in my local Postgres database)
Practitioner p = new Practitioner(providerName: 'p')
p.save(flush:true, failOnError: true)
Error
grails.validation.ValidationException: Validation Error(s) occurred during save():
- Field error in object
'com.transcendinsights.dp.measureresult.snapshot.Practitioner' on field 'entityId': rejected value [null]; codes
Super thanks for helping!
Related
I am trying to learn how to use prisma with a psql database.
I'm running into an issue using references where the id is a uuid string.
I have a user model with:
model User {
id String #id #default(dbgenerated("gen_random_uuid()")) #db.Uuid
request Request?
createdAt DateTime #default(now()) #db.Timestamptz(6)
updatedAt DateTime #default(now()) #updatedAt #db.Timestamptz(6)
}
model Request {
id Int #id #default(autoincrement())
user User #relation(fields: [id], references: [id])
// I also tried making the relation field userId
createdAt DateTime #default(now()) #db.Timestamptz(6)
updatedAt DateTime #default(now()) #updatedAt #db.Timestamptz(6)
}
When I try to migrate this, I get an error that says:
failed to apply cleanly to the shadow database. Error: db error:
ERROR: foreign key constraint "Request_userId_fkey" cannot be
implemented DETAIL: Key columns "userId" and "id" are of incompatible
types: text and uuid.
The prisma documents dont show an example using uuid.
The example they do give has a second parameter in the Profile model which has a userId as an Int. I tried adding this to my Request model (as an int, as a string and as a uuid). None of these worked.
model User {
id Int #id #default(autoincrement())
email String #unique
name String?
role Role #default(USER)
posts Post[]
profile Profile?
}
model Profile {
id Int #id #default(autoincrement())
bio String
user User #relation(fields: [userId], references: [id])
userId Int
}
How can I reference a userId when it is generated using uuid?
This segment of the prisma documentation suggests (if I have understood it correctly), that any of String or Int or enum should work to recognise a uuid:
Relational databases Corresponding database type: PRIMARY KEY
Can be annotated with a #default() value that uses functions to
auto-generate an ID:
autoincrement() cuid() uuid() Can be defined on any scalar field
(String, Int, enum)
When I try adding the pgcrypto extension to psql, I try to run the migration again and get an error that has less verbose messaging, but still similar issue:
Error parsing attribute "#relation": The type of the field id in the
model Request is not matching the type of the referenced field id
in model User.
I have seen this discussion which suggests somehow lying to prisma. I am not clever enough to understand the gist of what the lie is supposed to be or how to do it.
Someone on github suggested using this referencing syntax in the request model:
user User #relation(fields: [userId], references: [id])
userId String #unique #db.Uuid
I tried it as above, and without the #unique flag, but I still get a migration error that says that uuid and text are incompatible references. I can't find a section of the prisma documentation that addresses how to make uuid references compatible with relation models.
fyi: the migration file for the attempt above shows the following:
CREATE TABLE "Request" (
"id" SERIAL NOT NULL,
"userId" UUID NOT NULL,
CONSTRAINT "Request_pkey" PRIMARY KEY ("id")
);
You will have to use the annotation #db.Uuid on the reference column userId, read more about it here.
Example:
model Request {
id Int #id #default(autoincrement())
user User #relation(fields: [userId], references: [id])
userId String #db.Uuid
...your other stuff
}
In your Request model is missing the foreign key userId with #db.Uuid this will make postgreSql use the uuid type on a column and #relation the field name must be the same as the foreign key like this #relation(fields: [userId]). The complete code should look like this:
model User {
id String #id #default(dbgenerated("gen_random_uuid()")) #db.Uuid
request Request?
createdAt DateTime #default(now()) #db.Timestamptz(6)
updatedAt DateTime #default(now()) #updatedAt #db.Timestamptz(6)
}
model Request {
id Int #id #default(autoincrement())
user User #relation(fields: [userId], references: [id]) <-ADD userId here
userId String #db.Uuid <-ADD THIS
createdAt DateTime #default(now()) #db.Timestamptz(6)
updatedAt DateTime #default(now()) #updatedAt #db.Timestamptz(6)
}
You can do this with other types, here are some examples: https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#string
I had a similar error and it was because I did not change the type of the relation's ID from Int to String from the example.
If you update the Request model to look like this, does it work?
model Request {
id Int #id #default(autoincrement())
user User #relation(fields: [id], references: [id])
userId String // <- this was missing
createdAt DateTime #default(now()) #db.Timestamptz(6)
updatedAt DateTime #default(now()) #updatedAt #db.Timestamptz(6)
}
I think that the Felix Hagspiel answer is the solution. I could add you should remove the failed generated migration sql (by removing the folder) and retry it again after fixing the problem.
I am working with Grails application. I am using Apache Shiro security plugin for my grails application. I am trying to use findBy query on my User domain class with Or and And condition but it gives me an error.
My Domain Class
class ShiroUser {
String firstName
String lastName
String username
String email
String passwordHash
String userStatus
static hasMany = [ roles: ShiroRole, permissions: String ]
static constraints = {
username(nullable: false, blank: false, unique: true)
email(nullable: false, blank: false, email: true,unique: true)
}}
I have executed following query:
ShiroUser.findByUsernameOrEmailAndUserStatus(params?.username,params?.username,'Active')
I get following error:
Message: No property found for name [usernameOrEmail] for class [class com.chatportal.ShiroUser]
But If I execute query with only Or condition then it works fine.
ShiroUser.findByUsernameOrEmail(params?.username,params?.username)
Anyone please help me that what is wrong with my condition when I used Or and And condition with findBy ?
"You can combine as many criteria as you like, but they must all be combined with And or all Or. If you need to combine And and Or or if the number of criteria creates a very long method name, just convert the query to a Criteria or HQL query."
I'm using the grails database migration plugin: runtime ':database-migration:1.4.1'. For the initial changelog everything seems to work, even going from an H2 development database to mysql.
However, I wanted to test an actual model change, and I'm getting an error I can't figure out.
We have the following User model:
class User {
// spring security params:
transient springSecurityService
String username
String password
// Added this to test model changes:
String removeme
...
static mapping = {
password column: '`password`'
}
}
When I go to generate the diff, i.e.
grails dbm-gorm-diff --add change_test.groovy
I get the following exception:
liquibase.exception.DatabaseException: org.h2.jdbc.JdbcSQLException: Column "PASSWORD" not found; SQL statement:
SELECT password FROM user WHERE 1 = 0 [42122-176]
at liquibase.snapshot.jvm.JdbcDatabaseSnapshotGenerator.createSnapshot(JdbcDatabaseSnapshotGenerator.java:251)
at liquibase.snapshot.DatabaseSnapshotGeneratorFactory.createSnapshot(DatabaseSnapshotGeneratorFactory.java:69)
at liquibase.diff.Diff.compare(Diff.java:71)
at grails.plugin.databasemigration.GormDiff.compare(GormDiff.groovy:45)
at grails.plugin.databasemigration.ScriptUtils.createAndPrintFixedDiff(ScriptUtils.groovy:244)
at DbmGormDiff$_run_closure1$_closure2$_closure3.doCall(DbmGormDiff:53)
at grails.plugin.databasemigration.MigrationUtils.executeInSession(MigrationUtils.groovy:137)
at DbmGormDiff$_run_closure1$_closure2.doCall(DbmGormDiff:50)
at grails.plugin.databasemigration.ScriptUtils.executeAndWrite(ScriptUtils.groovy:104)
at DbmGormDiff$_run_closure1.doCall(DbmGormDiff:49)
Caused by: org.h2.jdbc.JdbcSQLException: Column "PASSWORD" not found; SQL statement:
SELECT password FROM user WHERE 1 = 0 [42122-176]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:344)
at org.h2.message.DbException.get(DbException.java:178)
at org.h2.message.DbException.get(DbException.java:154)
at org.h2.expression.ExpressionColumn.optimize(ExpressionColumn.java:148)
at org.h2.command.dml.Select.prepare(Select.java:831)
at org.h2.command.Parser.prepareCommand(Parser.java:248)
at org.h2.engine.Session.prepareLocal(Session.java:442)
at org.h2.engine.Session.prepareCommand(Session.java:384)
at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1188)
at org.h2.jdbc.JdbcStatement.executeQuery(JdbcStatement.java:75)
at liquibase.snapshot.jvm.JdbcDatabaseSnapshotGenerator.isColumnAutoIncrement(JdbcDatabaseSnapshotGenerator.java:842)
at liquibase.snapshot.jvm.JdbcDatabaseSnapshotGenerator.readColumns(JdbcDatabaseSnapshotGenerator.java:369)
at liquibase.snapshot.jvm.JdbcDatabaseSnapshotGenerator.createSnapshot(JdbcDatabaseSnapshotGenerator.java:244)
I can simply remove the removeme column and everything works as expected. This is only in our dev environment too, so only regarding the H2 database.
I solved this pretty much based on this answer:
How can I use Grails DB Migration with Spring Security and the default DB, H2?
Changed this
static mapping = {
password column: '`password`'
}
to
static mapping = {
password column: 'passwd'
}
Basically the above is preferred (IMO) because it avoids confusion in the database engine, and having to deal with weird escaping -- by just using something that isn't generally a reserved word.
My Grails application and bootstrap work fine when dbCreate="create", but when I change it to dbCreate="update", I get object create validation errors in bootstrap. I'd just like my data to persist when I restart the application. From the error message, it appears I'm violating a unique constraints. Maybe the database isn't getting purged on restart? I've tried "create-drop"
Here is the code and error message below. Any insight is appreciated.
development {
dataSource {
dbCreate = "create-drop" // one of 'create', 'create-drop', 'update', 'validate', ''
url = "jdbc:h2:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;"
}
}
class BootStrap {
def init = { servletContext ->
def adminRole = new com.testapp.Role(authority: 'ROLE_ADMIN').save(failOnError: true)
def userRole = new com.testapp.Role(authority: 'ROLE_USER').save(failOnError: true)
}
Message:
Validation Error(s) occurred during save():
- Field error in object 'com.testapp.Role' on field 'authority': rejected value [ROLE_ADMIN]; codes [com.testapp.Role.authority.unique.error.
default message [Property [{0}] of class [{1}] with value [{2}] must be unique
I think you must have already created the Role with Authority "ROLE_ADMIN" or "ROLE_USER". The second time you are running with update gives an error because of unique constraint. An attempt is being made to create role with same Authority names and it throws error.
You should apply a condition such that if a role already exist, you should not try to create the same again.
I developed application using grails 2.1.2 then I upgrade to 2.2.0
I have a domain class
class Concurrence {
Concurrence parent = null
Request request
Person approver
int status = 0
Date processed = null
}
class Request {
String no
Folder folder
String fiscalYear
String notes
static hasOne = [category: Category, channel : Channel]
Date created
Date submitted = null
Date approved = null
Date updated
Person requestor
int status = 0
boolean deleted = false
Person processedBy = null
boolean processed = false
Date processedDate = null
static hasMany = [documents:RequestDocument, concurrences:Concurrence, approvals:Approval, finalApprovals:FinalApproval, memos:Memo]
}
there is a property 'request' on Concurrence
Previously everything is ok, but after I use grails 2.2.0, that domain can't be saved,
Field 'request_id' doesn't have a default value
any suggestion how to solved this problem? Or I must downgrade to 2.1.2 or rename request property name?
best regards
The variable reqeust is a keyword in Grails that references the request object. With that said I think your first step should be picking a variable name that does not conflict with any default Grails objects.