Grails - List of Long not getting saved - grails

I have a domain class similar to the following:
class Record {
Long id
List numbers = []
String description
void recordNumber(Long number) {
//requirements, validations, etc.
numbers << number
}
}
Then I defined a Web service similar to the code below:
class RecordController extends RestfulController {
def recordNumber(Record record) {
def number = getNumberFromRequest() //request.JSON, request.XML, etc.
if (record) {
record.recordNumber(number)
record.save(flush: true, failOnError: true)
}
}
}
However, the numbers on the list don't seem to get saved, because when I retrieve a Record, the list empty. I have test for the code and it seems ok. Could it also be that the list is lazily loaded?

You are saving a new record instance each time the action is called. You should load it out of the DB instead:
def recordNumber( Long id ){
def record = Record.get id
def number = getNumberFromRequest() //request.JSON, request.XML, etc.
//....
}

So based on this answer from a previous StackOverflow question, I updated the code as follows:
class Record {
static hasMany = [numbers: Long]
Long id
String description
void recordNumber(Long number) {
//requirements, validations, etc.
addToNumbers number
}
}
It would seem that if a collection is meant to be persistent, it has to be declared this way, or be mapped in some other methods; I'm just not sure what those other methods are.

Related

Grails enum as domain property intermittently saving as ordinal value in database

Grails 2.3.7, Java 1.7, tomcat
For no apparent reason(that I can see) the reviewResults property of the Review domain sometimes saves as the ordinal value of the enum.
The database schema says that the column is a varchar type.
Sometimes NA is saved as NA, however, sometimes it is saved as 0.
This is the same with passed, except passed is saved as 1 sometimes.
Any ideas why this might be happening?
abstract class Work {
// Nothing defined in here related
// to the review domain enum.
}
The Domain class in question.
class Review extends Work {
Results reviewResults
String notes
enum Results {
NA,
Passed,
Error
}
static constraints = {
reviewResults(nullable: true, enumType: 'string')
}
// Is this redundant if it is already declared in the constraints?
static mapping = {
reviewResults enumType: 'string'
}
}
The Domains related controller.
// Reviews created with Quartz job, results property is not set.
class ReviewController {
def reviewService
def show(Long id) {
def reviewInstance = Review.get(id)
def reviewResultsOptions = []
reviewResultsOptions.addAll(com.mycompany.app.Review.Results.values())
[reviewInstance: reviewInstance, reviewResultsOptions: reviewResultsOptions]
}
def closeWork(Long id, String reviewResults, String notes) {
def review = Review.get(id)
review.reviewResults = Review.Results.valueOf(reviewResults)
def result = reviewService.closeReview(review, notes)
}
}
The service for the controller/domain.
class ReviewService {
def workService
Review closeReview(Review work, String notes) {
work.notes = notes
workService.closeWork(work)
return work.errors.allErrors.empty ? work : null
}
}
The service where the Review object is finally saved.
class WorkService {
Tracking closeWork(Work workInstance) {
def tracked = new Tracking()
workInstance.setStatus(status)
workIntance.setClosed(new Date())
WorkInstance.save(flush: true)
// Set some tracking properties and save and return the tracking object.
}
}

How can I get objects based off of certain associations?

I have the following domain classes (Only trying to show what is needed to get the idea) :
class Scholarship {
static hasMany = [grades:Grade]
}
and
class Grade {
String id
String description
}
In words I would like to, "Get all scholarships where the associated grade_id = myId". I would like to accomplish this using grails domain classes and not using sql. Any help appreciated
Are you looking for something like this?...
def results = Scholarship.withCriteria {
grades {
// myId must be defined somewhere above...
idEq myId
}
}
EDIT
A comment below adds to the original question and asks what if another relationship was expressed like this...
class Scholarship {
static hasMany = [grades:Grade,majors:Major]
}
The query I show above would still be exactly the same. The fact that there is a majors collection would not be relevant unless you wanted to include some attribute of Major to also be part of the criteria, which could look something like this...
def results = Scholarship.withCriteria {
grades {
// myId must be defined somewhere above...
idEq myId
}
majors {
// only return Scholarship instances which
// contain a Major with the name 'Mechanical Engineering'
eq 'name', 'Mechanical Engineering'
}
}
I hope that helps.

grails unknown number of model objects in the view

Working in Grails 2.2
I have a situation where I need to be able to handle an unknown number of CommitteeMembers in the view. These need to be both created and displayed.
Each one has the usual attributes - name, address, contact information, userid.
I understand that if I name form fields the same name, Grails will return a collection for me to iterate over. In this case, however, I am faced with this situation:
cm_firstname
cm_lastname
cm_address
cm_email
cm_userid
So does this mean I will be given collections of each of these fields? That is not as useful as there is no way to corelate the various firstnames with the correct lastnames, etc.
I am enjoying Grails and am looking forward to your feedback.
You can use Grails Command objects to do this work for you. Here's an example in a SO question. Basically you will have a single collection of CommitteeMembers that will be populated in your controller thorugh data binding.
As #Gregg says, in the view you need the fields to have an index.
class MyDomain {
String name
}
class MyDomainCommand {
List<MyDomain> instances = ListUtils.lazyList([], FactoryUtils.instantiateFactory(MyDomain))
}
class MyController {
def save() {
MyDomainCommand command = new MyDomainCommand()
bindData(command, params, [include: 'instances'])
}
}
I'll tell you what I do, which may or may not be the best option. I do this mainly because I don't like data binding.
For your case as an example, I would name my fields: "cm.firstName, cm.lastName, cm.address, cm.email, cm.userId".
If you are in a service:
GrailsWebRequest webUtils = WebUtils.retrieveGrailsWebRequest()
List committeeMembers = [].withDefault {new GrailsParameterMap([:], webUtils.getCurrentRequest())}
In a controller:
List committeeMembers = [].withDefault {new GrailsParameterMap([:], request)}
Then
params.cm.each { k, v ->
if (v instanceof String[]) {
v.eachWithIndex { val, idx ->
committeeMembers[idx]."$k" = val
}
}
else {
committeeMembers[0]."$k" = v
}
}
Then you can do:
committeeMembers.each {
<Create from it.firstName, it.lastName, etc>
}

Grails: querying hasMany association

I know there are several questions on this subject but none of them seem to work for me. I have a Grails app with the following Domain objects:
class Tag {
String name
}
class SystemTag extends Tag {
// Will have additional properties here...just placeholder for now
}
class Location {
String name
Set<Tag> tags = []
static hasMany = [tags: Tag]
}
I am trying to query for all Location objects that have been tagged by 1 or more tags:
class LocationQueryTests {
#Test
public void testTagsQuery() {
def tag = new SystemTag(name: "My Locations").save(failOnError: true)
def locationNames = ["L1","L2","L3","L4","L5"]
def locations = []
locationNames.each {
locations << new Location(name: it).save(failOnError: true)
}
(2..4).each {
locations[it].tags << tag
locations[it].save(failOnError: true)
}
def results = Location.withCriteria {
tags {
'in'('name', [tag.name])
}
}
assertEquals(3, results.size()) // Returning 0 results
}
}
I have validated that the data is being created/setup correctly...5 Location objects created and the last 3 of them are tagged.
I don't see what's wrong with the above query. I would really like to stay away from HQL and I believe that should be possible here.
Welcome to hibernate.
The save method informs the persistence context that an instance should be saved or updated. The object will not be persisted immediately unless the flush argument is used
if you do not use flush it does the saves in batches so when you setup your query right after the save it appears that the data is not there.
you need to add
locations[it].save(failOnError: true, flush:true)
You should use addTo* for adds a domain class relationship for one-to-many or many-to-many relationship.
(2..4).each {
locations[it].addToTags(tag)
}

How to make a query with usage of like operator over a string collection in GORM

Assume a domain class called User. User class looks like this:
class User {
List<String> values
}
The collection values contains strings like "http://example.com/x", "http://google.com/y", "http://google.com/z" and so on...
Let's say we want to build a query which gets all the users that have specific string in the collection values (e.g. "google.com"). Something like this:
def criteria = User.createCriteria()
def results = criteria.listDistinct () {
and {
user.values.each { like('someField', '%${it}%') }
}
}
Any ideas?
I have found the answer by experimentation. The solution is:
def criteria = User.createCriteria()
def results = criteria.listDistinct () {
and {
user.values.each { like('someField', '%'+it+'%') }
}
}
I am not sure what you are doing with your suggested answer.
I have never seen that usage of each in the criteria query before.
This question has been asked many times before but never given an answer.
The problem is that you are queriyng a String association, which is not a domain class. If you would make your own String domain class for example ondrej.String { String strValue } then you would be able to do :
User.withCriteria {
values { ilike("strValue", "...") }
}
The problem is not having access to the value of the String object. The value of the String class is called value, but it is a char array, so I do not believe the following will work:
User.withCriteria {
values { ilike("value", "...") }
}
You could try using :
User.withCriteria {
values { ilike("toString", "...") }
}
or something else instead of toString ... I do not have the possibility to test this right now.
Hope that helps
After a lot of trying and researching, I found this will work with Grails 2.4.0, I don't know about older versions.
Cat.withCriteria {
createAlias('nicknames', 'n')
ilike 'n.elements', '%kitty%'
}
The trick is to use 'n.elements'

Resources