Grails domain ID column validation issue - grails

I have a simple domain object
class MyDomain
{
String id
String name
static constraints =
{
id unique:true
name nullable:true
}
static mapping =
{
table 'schema.MyDomain'
id column:'MY_ID', type:'string', generator:'assigned'
}
}
The issue I am having is when I call validate on the object, it returns true even when the id field is null. I had thought that all columns were nullable:false unless explicitly stated otherwise. If I change the line
id unique:true
to
id unique:true, nullable:false
then it seems to work fine. My main question is, why do I have to explicitly set nullable for the ID column? It is just a small line of code, but I don't like just adding in the tag of code without understanding why in case it is a symptom of a bigger problem.

The id column is auto generated and auto populated(when versioning is turned on[true by default]) and you shouldn't have to declare a new one.
This default id column is nullable:false by default and you can still set the mapping properties and id generation strategies like you have done above against it.
However if you want to define the default constraints for all domain in you app, you can do it globally by setting thwe following in your config.groovy file.
grails.gorm.default.constraints = {
myShared(nullable:true, size:1..20)
}
For more on constraints see the Grails documentation.

Related

Grails data won't bind if the id column is renamed

Grails will create an id and a version columns from a domain class automatically. I want to use my own column for the primary key. So, I follow the doc to change the mapping.
class book {
String isbn
static mapping = {
id generator: 'assigned', name: 'isbn'
}
}
So far so good. The isbn column is now the primary key.
I use generate-all to create the view and controller. However, the data binding won't work anymore.
Create and Save work no problem. It binds a book to the view. I can add a new book to the database no problem.
def create() {
respond new Book(params)
}
def save(Book book) {
if (book == null) {
notFound()
return
}
...
}
But the Update action does not bind. book is null after I click the Update button from the Edit view.
def update(Book book) {
if (book == null) {
notFound()
return
}
...
}
The codes generated by generate-all in the Save and Update actions are the same. I don't understand why it will bind the book to the Save action but not to Update action.
Would you show me the problem please?
Many Thanks!
I think I figure it out. When I bind an object to a view, Grails is hardcoded to look for the id property. It has to be spelled "id". If there is no "id" property in the domain class, Grails will not bind.
The way I figure this out is to look at the actual HTML generated by the server.
If there is an id property bind to the view, I see the HTML has the ../controller/action/id link.
If the id property is missing, the HTML link is just ../controller/index
I am new to Grails. So, I guess in order for the binding to work, I need to have an id property for Grails to put in the link.
I think this is a REST call. I don't know what REST is though.
So, I will try to add an dummy id property to my Book domain class to see if Grails will take the bait. I will set up the domain so Grails won't generate the id column in the database table. The id property is used locally only. No need to save it to the database.
class book {
String isbn
String id
static mapping = {
id generator: 'assigned', name: 'isbn'
}
}
I will copy the isbn value to the id property. I am not sure if this will work or not. I hope Grails will generate the link in the view with the isbn string in the id property instead of the default integer id value.
../controller/action/978-3-16-148410-0

grails: primary key from view

I have a requirement to create Employee and Role domain with ids which should be inserted at the time of creation and not manually inserted via code.
Following is attached code for Role.groovy
package pocgrails1
class Role{
String roleId
String roleName
static hasMany = [RoleACL]
static mapping = {id generator: 'assigned',name:"roleId",type:'string'}
static constraints = {
roleName blank:false
roleId blank:false
}
String toString(){
return id
}
}
I am having issues while generating the primary key from the view.
By default the scaffold does not generates the field to insert the primary key value.
I already have looked into several blogs and posts but none were of much help.
What should be the correct approach for this.
Many thanks in advance.
Rohit
Hard to understand what do you want to do. If you want to change primary id key define it as String id and change mapping:
class Role{
String id
static mapping = {
id column: 'role_id', generator: 'assigned'
}
}
When you save object an id will be generated for you and persisted to database, no need to create anything manually

Property [] of class [] can not be null error in Grails

I am new to Grails and getting this error on two out of my three domains when I run the project on all the domains content. The domain the works is
class Location {
def scaffold = true
String company
String name
String address
static belongsTo=[company:Company]
static constraints = {
}
}
The domain that does not work is
class Report {
def scaffold = true
String title
String location
Date published
static belongsTo=[location:Location]
static constraints = {
}
}
I can not see the structural or syntax issue that is trowing the errors. I have been trying a variety of adds and subtracts and can not seem to find anything that address this error at a basic level. Again I have just started using Grails and Groovy
After doing the changes told by #araxn1d, you should also check the constraints. By default all properties are not nullable (that's why you're getting for example the error for the title property)
If you already have data in your database you have two options:
Update your database and set the correct values in each table or row
Set each property in the domain as nullable. For example
static constraints = {
title nullable:true
}
Are you creating a Report with no properties set? By default, Grails will check that all properties are not null. If you want to allow the user to leave a certain field undefined (null), then you have to explicitly tell Grails in the constraints map:
static constraints = {
propertyName nullable: true
}
Seems like error is in this line:
String location
location is String type, but should be Locationtype. The same as String company in Location domain should be Company company.
I think the problem is that you've changed the structure of the domain class after you generated the automatically created views/controller for the domain.
I fixed it by just deleting the offending domain along with the controller/views file and recreating them. I'm sure you could root through and find the offending code though.

Grails URL mappings

In my Grails app I have a couple of domain classes, say Author and Book. I'm using the default URL mappings:
static mappings = {
"/$controller/$action?/$id?"{
constraints {
// apply constraints here
}
}
}
So the relative URL to show the book with id 2 is /book/show/2 or for the author with id 5 it's /author/show/5. Both the Author and Book classes have a unique name property.
I would prefer the URLs to show an author or book use the name rather than the database ID to identify the book/author, e.g. /author/show/shakespeare and /book/show/ulysses. Is this achievable without changing the domain classes such that the name field is the id (primary key)?
You could just pass strings (e.g. "shakespeare") as params.id and then instead of doing a:
Author.get(params.id)
in your controller method, do:
Author.findByName(params.id)
As far as I know, the id parameter (when used with URLs) doesn't have to be a long.

Grails domain class: unique constraint for multiple columns

Suppose a simple Grails domain class:
class Account {
String countryId;
String userName;
String password;
static constraints = {
...???...
}
}
It is required that user names are unique for a particular countryId, thus there must be a unique contraint on two columns. How to express this in the constraints definition?
userName(unique: ['countryId'])
You can include as many other properties in the array that make up the other properties that must be considered in the "unique" constraint on the username.
So, for example if you wanted to make userName unique within a countryId and provinceId it would look like this:
userName(unique: ['countryId', 'provinceId']

Resources