I did a Google search but came up dry on anything that explained what is happening...
I have the following domain class:
class Company {
Integer companyId
String name
static constraints = {
companyId unique: true
name blank: false
}
String toString(){
return name
}
}
When I do a 'new Company(params)' in the controller with the passed in values, it returns an object with the 'companyId' field set to null. I've double checked the values in 'params' and both 'params.name' and 'params.companyId' are set to non-null values.
What am I doing wrong?
I have another domain/controller (created by someone else now gone) doing something similar that works fine so I must be missing something.
I'm new to Grails/Groovy and any/all advice welcome.
Related
I am developing a Grails 2.3.7 application and I'm having trouble changing a domain property with a select box. Every time I try to change the property and save, I get a HibernateException: identifier of an instance of Ethnicity was altered from X to Y. I don't want to change the ID of the ethnicity, I simply want to change the ApplicationPersons ethnicity from one to another.
A few things to note:
I am using the same controller action to create AND update the person.
Setting personInstance.ethnicity to null right before personInstance.properties = params will make the save work, but I
don't know why, and I don't want to do this for every association
that I want to change.
I realize the domain model seems odd. It is a legacy DB that I cannot change.
Here are my domain classes:
class ApplicationPerson implements Serializable {
Integer appId
Integer applicationSequenceNumber
String firstName
String lastName
Ethnicity ethnicity
static mapping = {
id composite: ['appId', 'applicationSequenceNumber'],
generator: 'assigned'
}
}
class Ethnicity {
String code
String description
static mapping = {
id name: 'code', generator: 'assigned'
}
}
Here is my _form.gsp to update the Ethnicity (I removed all the other properties that are saving just fine):
<div class="fieldcontain ${hasErrors(bean: personInstance,
field: 'ethnicity', 'error')} ">
<label for="ethnicity">Ethnicity</label>
<g:select id="ethnicity"
name="ethnicity.code"
from="${Ethnicity.list()}"
optionKey="code"
value="${personInstance?.ethnicity?.code}" />
</div>
And lastly, my controller action that the form POSTs to:
def save() {
Application app = applicationService.getCurrentApplication()
// Find/Create and save Person
ApplicationPerson personInstance = app.person
if (!personInstance) {
personInstance =
new ApplicationPerson(appId: app.id,
applicationSequenceNumber: app.sequenceNumber)
}
personInstance.properties = params
if (!personInstance.validate()) {
respond personInstance.errors, view:'edit'
return
}
personInstance.save flush:true
redirect action: 'list'
}
Modify the name in the select element from ethnicity.code to personInstance.etnicity.code as shown below:
<g:select id="ethnicity"
name="personInstance.ethnicity.code"
from="${Ethnicity.list()}"
optionKey="code"
value="${personInstance?.ethnicity?.code}" />
The name of selected option gets bound to params as key and the selected value as the
value against the key. Using ethnicity.code would try to modify the primary key of an existing ethnicity instead of modifying the ethnicity of an application person.
UPDATE
Above change in name is optional (can be used in case you don't need params to be assigned as properties of domain class). Previous name ethnicity.code should work as well but below changes are also required in the controller action in order to set ethnicity:
//or use params.ethnicity.code
//if name is ethnicity.code
person.ethnicity = Ethnicity.load(params.personInstance.ethnicity.code)
//or use params if name is ethnicity.code
person.properties = params.personInstance
Load an existing Ethnicity based on the passed in code and then set it in person before setting properties.
The issue lies with code being the primary key of Ethnicity. If Ethnicity had a separate identity column (for example, the default Long id) then your exact implementation in question would work with the help of data binding. But since it is mentioned that you are working with legacy database, I suppose you won't be able to modify the tables to add another column for id. So your best bet will be to load(cheap compared to get, as row is loaded from hibernate cache) ethnicity from the passed in code and then set it to person.
You can also see try caching the Ethnicity domain if possible because that will be master data and a good candidate for caching.
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
I'm working inside of a service and I have the following two calls:
def user = User.get(2)
user = user.get(1)
This example is contrived, but it illustrates my issue. For the first line I get the user with an id of 2. At this point I have a fully populated domain object and all is well. The fields are populated in the database, so it's not as obvious as missing data. If I call User.get(1)first I'll have a correctly populated domain object. However, when I make the second call (the reassignment) I get a semi populated record. I'm missing the User's firstName, lastName, and email fields. This seems like a pretty simple use case and I've never had this issue in the past. Am I doing something really dumb here? Has something like this happened to anyone else?
Some field definitions:
String username
String emailAddress
String firstName
String lastName
String password
String photoUrl
String title
String contactPhone
Corresponding constraints:
username(blank: false, unique: true)
photoUrl(nullable: true)
title(nullable: true)
contactPhone(nullable: true)
welcomeText(nullable: true)
emailAddress(blank: false, nullable: false)
firstName(blank: false)
lastName(blank: false)
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.
There is domain class with natural key defined as below
class InterestGroup {
String intGrp
String name
static constraints = {
intGrp(blank: false, maxSize: 4, unique: true)
name(blank: false, minSize: 10, maxSize: 50)
}
static mapping = {
id generator: "assigned", name: "intGrp", type: 'string'
}
String toString() { "${intGrp}"}
}
I try to modify standard scaffolding to make possible changes of name field.
In standard code there is save() method called and it checks all field, and of course record could not be updated because record with same key exists. When i just assign field value
interestGroupInstance.name = params?.name
name is updated but, not checked against domain class constaint.
What is the best way to realize CRUD operation with natural keys based tables?
Best regards
Krzysiek
I don't think I'm understanding you. What are you trying to do? You are trying to update your group's name and it doesn't seem to make any validation?
The reference documentaion says: "The save method informs the persistence context that an instance should be saved or updated. The save method returns null if validation failed and the instance was not saved and the instance itself if successful.". So it should be calling validate methos when you call save methos on your domain class object.
Could you please post an example?