auto incrementing integer field in Grails - grails

I have field int displayOrder = 1 in Grails domain object and would like to increment it by 1 each time the domain object gets saved.
If I have domain object Widget that has one-to-many relationship with Pix, every time Widget gets a new Pix, Pix needs to have displayOrder incremented.
What would be the most prudent way of setting this up? Preferably count should start from 1 to keep confusion to minimum when someone wants to change the display order. I thought about just duplicating the ID, but then we are possibly looking at displayOrder of 1123, followed by 1169 , etc., so that's not a practical option.
The collection of Pixes belonging to Widget is a sortedSet.

You could also do a Named Query to get the last max value of the Pixes, which would work in scenarios where the display orders have skips and jumps.
class Widget {
static hasMany = [pixes: Pix]
...
}
class Pix {
static belongsTo = [widget: Widget]
static namedQueries = {
selectMaxDisplayOrderForWidget { widgetInstance ->
eq('widget', widgetInstance)
projections {
max('displayOrder')
}
uniqueResult = true
}
}
...
}
Then:
def widget = retrieveOrCreateWidget()
def pix = new Pix(propertyA: "A", ..., displayOrder: Pix.selectMaxDisplayOrderForWidget(widget).list(), widget: widget)
If you want to reinitialize the display order numbers after a deleted Pix so they are sequential for a Widget, per your comment to #Jarred Olson, you could do:
Pix.findAllByWidgetAndDisplayOrderGreaterThan(widget, deletedPixDisplayOrder, [sort:'displayOrder',order:'asc']).eachWithIndex { pixInstance, idx ->
pixInstance.displayOrder = deletedPixDisplayOrder + idx
pixInstance.save()
}

I'd assume that your code looks something like this then:
class Widget {
static hasMany = [pixes: Pix]
...
}
class Pix {
static belongsTo = [widget: Widget]
...
}
def widget = retrieveOrCreateWidget()
def pix = new Pix(propertyA: "A", ..., displayOrder: 1, widget: widget)
pix.save()
widget.addToPixes(pix)
widget.save()
You can determine the displayOrder by the size of pixes:
def widget = retrieveOrCreateWidget()
def pix = new Pix(propertyA: "A", ..., displayOrder: widget.pixes.size() + 1, widget: widget)
EDIT:
If all you need to do is be able to sort a Widget's Pixes by when they were created you could add dateCreated to Pix. This automatically gets set by Grails when a Pix is created. Then you wouldn't have to increment/decrement the value when you add and delete.

Related

How to save addTo in order by given date/id?

I need some help on my API, when I'm on web, the order is saving correct, but when its on API, it goes all wrong:
def test = parseJSON.sort { a, b -> a.ID <=> b.ID } //or dateTime, will print the same
//order when I print each of them
[IDWeb:0, conductivity:0, ReportId:2, dissolvedOxygen:0, levelWater:1, ID:1, ph:0, redoxPotential:0, temperature:0]
[IDWeb:0, conductivity:0, ReportId:2, dissolvedOxygen:0, levelWater:0, ID:2, ph:0, redoxPotential:0, temperature:0]
[IDWeb:0, conductivity:0, ReportId:2, dissolvedOxygen:0, levelWater:0, ID:3, ph:0, redoxPotential:0, temperature:0]
[IDWeb:0, conductivity:0, ReportId:2, dissolvedOxygen:0, levelWater:4, ID:4, ph:0, redoxPotential:0, temperature:0]
test.each{
def sample = new SampleWater()
sample.levelWater = it.levelWater
sample.conductivity = it.conductivity
sample.dissolvedOxygen = it.dissolvedOxygen
sample.redoxPotential = it.redoxPotential
sample.ph = it.ph
sample.temperature = it.temperature
water.addToSamples(sample)
}
return water
My problem is that addTo is not saving in order. How can I solve this?
Make sure you have defined the type of samples as a List in your Water domain class so that we can maintain the insertion order:
class Water {
static hasMany = [samples: Sample]
List<Sample> samples = []
}
class Sample {
def levelWater
}
By default implementation of hasMany is of type Set which does not maintain the insertion order but is responsible for uniqueness.
Since, now you samples will be saved in the same order as they are inserted.
You have to specify with order you want to apply to the list of SampleWater in the "water" domain class.
i.e:
class BlogCategory {
static hasMany = [
entries : BlogEntry
]
static mapping = {
entries: sort:'dateCreated', order:'desc'
}
}
In this example BlogEntry will be ordered respect dateCreated.

Groovy removeAll closure not removing objects in Set

I'm using data binding with parent/child relationships in Grails 2.3.7 and am having trouble with deletes. The form has many optional children, and to keep the database tidy I'd like to purge blank (null) values. I've found some nice articles which suggest using removeAll to filter my entries but I can't get remove or removeAll to work!
For example... (Parent has 10 children, 5 are blank)
def update(Parent parent) {
parent.children.getClass() // returns org.hibernate.collection.PersistentSet
parent.children.size() // returns 10
parent.children.findAll{ it.value == null }.size() // returns 5
parent.children.removeAll{ it.value == null } // returns TRUE
parent.children.size() // Still returns 10!!!
}
I've read PersistentSet is finicky about equals() and hashCode() being implemented manually, which I've done in every domain class. What baffles me is how removeAll can return true, indicating the Collection has changed, yet it hasn't. I've been stuck on this for a couple days now so any tips would be appreciated. Thanks.
Update:
I've been experimenting with the Child hashcode and that seems to be the culprit. If I make a bare-bones hashcode based on the id (bad practice) then removeAll works, but if I include the value it stops working again. For example...
// Sample 1: Works with removeAll
int hashCode() {
int hash1 = id.hashCode()
return hash1
}
// Sample 2: Doesn't work with removeAll
int hashCode() {
int hash1 = id.hashCode()
int hash2 = value == null ? 0 : value.hashCode()
return hash1 + hash2
}
// Sample Domain classes (thanks Burt)
class Parent {
static hasMany = [children: Child]
}
class Child {
String name
String value
static constraints = {
value nullable: true
}
}
This behavior is explained by the data binding step updating data, making it dirty. (ie: child.value.isDirty() == true) Here's how I understand it.
First Grails data binding fetches the Parent and children, and the hashcode of each Child is calculated. Next, data updates are applied which makes child.value dirty (if it changed) but the Set's hashcodes remain unchanged. When removeAll finds a match it builds a hashCode with the dirty data, but that hashcode is NOT found in the Set so it can't remove it. Essentially removeAll will only work if ALL of my hashCode variables are clean.
So if the data must be clean to remove it, one solution is to save it twice. Like this...
// Parent Controller
def update(Parent parent) {
parent.children.removeAll{ it.value == null } // Removes CLEAN children with no value
parent.save(flush:true)
parent.refresh() // parent.children is now clean
parent.children.removeAll{ it.value == null } // Removes (formerly dirty) children
parent.save(flush:true) // Success!
}
This works though it's not ideal. First I must allow null values in the database, though they only exist briefly and I don't want them. And second it's kinda inefficient to do two saves. Surely there must be a better way?
hashCode and equals weirdness aren't an issue here - there are no contains calls or something similar that would use the hashCode value and potentially miss the actual data. If you look at the implementation of removeAll you can see that it uses an Iterator to call your closure on every instance and remove any where the closure result is truthy, and return true if at least one was removed. Using this Parent class
class Parent {
static hasMany = [children: Child]
}
and this Child
class Child {
String name
String value
static constraints = {
value nullable: true
}
}
and this code to create test instances:
def parent = new Parent()
5.times {
parent.addToChildren(name: 'c' + it)
}
5.times {
parent.addToChildren(name: 'c2' + it, value: 'asd')
}
parent.save()
it prints 5 for the final size(). So there's probably something else affecting this. You shouldn't have to, but you can create your own removeAll that does the same thing, and if you throw in some println calls you might figure out what's up:
boolean removeAll(collection, Closure remove) {
boolean atLeastOne = false
Iterator iter = collection.iterator()
while (iter.hasNext()) {
def c = iter.next()
if (remove(c)) {
iter.remove()
atLeastOne = true
}
}
atLeastOne
}
Invoke this as
println removeAll(parent.children) { it.value == null }

Create an autoincrement (non id) field in Grails & Oracle

I have to keep track of sequential submissions per fiscal year. Given the fiscal year '2015' then the numbering should be '2015001, 2015002, 2015003, etc'.
I have defined a domain class to keep track of these settings:
class MYAPPConfig {
String fiscalYear
Integer requestCount
static constraints = {
fiscalYear (size: 4..4, nullable: false)
requestCount(max: 999, nullable: false)
}
}
The idea is that for a new fiscal year I will add a new record and the 'requestCount' will be reset to 0 (or 1 depending on how Grails wants to manage it).
Ideally this field should be mapped to an Oracle sequence field. If that's not possible then should I manage the increment logic in a service method?
My Grails version is 2.4.2
Thanks.
I figured it out.
I took a different route (after more googling). I added dateCreated to my model which is managed by Grails so its updated automatically. So all I needed to do is get the record with the latest date (every year we will add a new record for the coming fiscal year). Take note of the [0] at the end of the call, that flattens the array of arrays returned and allows me to deal with a single object.
My model now looks like this ( MYAPPConfig.groovy ) :
class MYAPPConfig {
String fiscalYear
Integer requestCount
Date dateCreated
static constraints = {
fiscalYear (size: 4..4, nullable: false)
requestCount(max: 999, nullable: false)
}
}
I created the following service ( ManageRequestsService.groovy )
import grails.transaction.Transactional
#Transactional
class ManageRequestService {
def getNextTrackingId() {
def latestConfig = MYAPPConfig.listOrderByDateCreated(max:1, order: "desc")[0]
def latestFiscal = latestConfig.fiscalYear
Integer sequence = latestConfig.requestCount
sequence++
latestConfig.requestCount = sequence
latestConfig.save(flush:true)
return latestFiscal + sprintf('%03d', sequence)
}
}
And in my controller ( MyTestController.groovy ) I have:
class MyTestController {
def manageRequestsService
def test() {
def trackingId = manageRequestsService.getNextTrackingId()
render "Next id is: ${trackingId}"
}
}
Giving the following output ( http://localhost:8080/MYAPP/myTest/test ):
Next id is: 2015001
Refresh page!
Next id is: 2015002
Refresh again!
Next id is: 2015003

Grails: How to query objects in many to many mapping?

Hello I have the follwing domain classes.
class Student {
int age
static hasMany = [courses:Course]
}
class Course {
String name
static hasMany = [students:Student]
}
I want to find the Students taking Course (with id 1), with age 7.
Could I do that with dynamic finder or criteria builder or HQL?
I do not want to do following as it load all students so inefficient:
def course = Course.get(1);
course.students.findAll{ it.age == 7 }
def studs = Student.withCriteria {
eq('age', 7)
courses {
eq('id', 1)
}
}
It's in GORM doc, section "Criteria/Querying Associations".
You can use a dynamic finder:
def students = Student.findByCourseAndAge(Course.load(1), 7)
By using load() instead of get() you avoid retrieving the whole Course instance and just reference its id.
Another option is HQL:
def students = Student.executeQuery(
'from Student s where s.course.id = :courseId and s.age = :age',
[courseId: 1, age: 7])

Grails additional columns in table or list

I'm trying for several days to receive a list from my Data. The Domain looks like this:
class Alpha {
String a
String b
etc.
static hasMany = [beta:Beta]
}
class Beta {
String a
Integer foo
String status
static belongsTo = [alpha:Alpha]
static constraints = {
status(nullable:false, inList:["val1","val2","val3", "val4"])
}
}
I'd like to have in Alpha the sum of all Beta.foo and of all Beta.foo in a certain status. Best would be something like an additional row ( Integer sumVal1 ... ).
I tried named queries:
static namedQueries = {
erledigterProbeAufwend {
createAlias ('Beta', 'b')
eq ('b.status', 'val1')
projections {
groupProperty('b.alpha')
sum('b.foo', 'sumFooVal1')
}
}
}
But this just give me one sum at a time.
I'm looking forward to get some help on that.
Greetings
Bas
This could be calculated formula field, but with a subquery trick:
static mapping = {
betaCount formula: "(SELECT count(*) FROM Beta b WHERE b.alpha_id = id and b.status in('a', 'b'))"
}
Create transient variables in your Alpha class and populate them in an onLoad event.
class Alpha {
String a
String b
etc.
static transients = ["sumVal1",...]
static hasMany = [beta:Beta]
def onLoad = {
sumVal1 = ....
}
}

Resources