different types of null in groovy - grails

I have a method that looks like this:
static UserEvent get(long userId, long eventId) {
UserEvent.find 'from UserEvent where user.id=:userId and event.id=:eventId',
[userId: userId, eventId: eventId]
}
I'm calling it two times with some test data:
println UserEvent.get(1, 1) //I know this has value
println UserEvent.get(1,2) //I know this does not
The above two statements result in:
scheduler.UserEvent : null
null
Question
What is the difference? How can I write an If condition for when something is present or not..
Update
I'm creating the object like this:
def event = Events.findById(params.eventid)
def user = User.findById(params.userid)
UserEvent.create(user, event, true)

#tim_yates is right, the object that is retrieved doesn't have an id property. Looks like an M to M relationship.
So in the first case an instance is being returned but it's ID is null.
In the second case the object isn't found.
You can use something like:
def ue = UserEvent.get(userId, eventId)
if (ue && ue instanceof UserEvent) { //do something }
else { //do something else }
Hope this helps.

The first case returns an instance of UserEvent, which inside of an if statement, should return true. The second case returns null, which inside of an if statement, should return false.

Related

Logic error in null clause

hi I have the following function :
def signup(String name){
def x =Human.where{name == name}
if(x != null)
{
def myhuman=new Human(name: name)
if(myhuman.save() && myhuman.validate())
{
redirect(url:"https//localhost:8080")
}
}
else
{
return
}
}
It works fine. I can create people with different names and I can't create a person with the same name, however I was wondering in that if why do we check for x!=null, shouldn't we check for x == null because we first look if such a person exists and if does not we create it. I tried with x==null and I can't ever create Human, can someone explain?
You check for x != null because you can not perform operations on a null object now can you? In fact it's more Groovy to do the following:
if (!x) {
// Logic
}
This works because of the Groovy Truth.
If x == null validates to true, then you proceed as normal performing whatever operations you need. However, since in your case x is not null, x == null will validate to false and skip the if block. This isn't specific to Grails, it's general programming.
You can use an Elvis operator, if the user does not exist you create a new one.
When a Human exist, it has an id, so you check if has an id, if not, you save it and do the redirect.
You don't need to validate the object, the save method validates the object before saving it, and if it is not validated, returns false.
Human human = Human.findByName(name)?: new Human(name: name)
if(!human.id && human.save()){
redirect(url:"https//localhost:8080")
}else{
return
}

How can I put an if statement inside of a createCriteria in grails?

I'm new in grails and I have a problem. I have a method that receive some data and match the data with a createCriteria and return the data. It's working fine, but that I want to do now if match with the five params that I have in the method and if match return the data, if not match with the five params, try if match with four params and return the data, if not match with the four params, try if match with three and return the data....
But not really sure how can I put all this in a if statement and return my result.dataPerson or maybe I have to find another way to do it.
My method:
def getPersonData(String name, String surname, String address, String phone){
def searchdataPerson = ClientConfig.createCriteria()
def result = searchdataPerson.get{
and{
or{
eq('surname', surname)
isNull('surname')
}
or{
eq('address', address)
isNull('address')
}
or{
eq('phone', phone)
isNull('phone')
}
or{
eq('name', name)
isNull('name')
}
}
maxResults(1)
}
return result.dataPerson
}
I'm trying to do something like this but it doesn't work
def searchdataPerson = ClientConfig.createCriteria()
def result = searchdataPerson .get{
if(eq('name', name) && eq('surname', surname) && eq('address', address) && eq('phone', phone)){
}else if(eq('name', name) && eq('surname', surname) && eq('address', address)){
}
maxResults(1)
}
return result.dataPerson
I get this error:
java.lang.NullPointerException: Cannot get property 'dataPerson' on null object
I can't tell from your example what you are really trying to do but you can put if statements in side the closure anywhere normal Groovy language rules would allow:
def getPersonData(String name, String surname, String address, String phone){
def searchdataPerson = ClientConfig.createCriteria()
def result = searchdataPerson.get{
and{
if(surname != 'GooglyMoogly') {
or{
eq('surname', surname)
isNull('surname')
}
}
if(address != 'Caddyshack') {
or{
eq('address', address)
isNull('address')
}
}
// ...
}
maxResults(1)
}
return result.dataPerson
}
As Jeff has pointed out above you should really refer to result and you are getting the error because you are getting a result but then trying to return an entity or maybe event object hanging off the result.
What is dataPerson ? is it a relationship hanging off of ClientConfig i.e belongsTo or hasMany declaration in ClientConfig ?
From all of above it isn't exactly clear but to try and explain it another way, you could use HQL:
String query="""
select new map(c.name as name,c.surname as surname, d as dataPerson)
from ClientConfig c
left join c.dataPerson d where
(c.surname != 'GooglyMoogly' or c.surame is null or c.surname=:surname) and
(c.address != 'Caddyshack' or c.address is null or c.address=:address) and
(c.phone is null or c.phone=:phone) and
(c.name is null or c.name=:name) and
"""
def inputParams=[surname:surname,address:address,phone:phone,name:name]
def result = ClientConfig.executeQuery(query,inputParams,[readOnly:true,timeout:15,max:1])
result?.each { output ->
println "--- ${output?.name} ???? ${output.surname} ???? "
output?.dataPerson.each { dp ->
println "--- ${dp.name} ???? "
}
}
Some of above may not be correct but may help you decipher what it is you are trying to achieve.
In the above HQL statement I have done a left join between clientConfig and dataPerson. This is assuming
class ClientConfig {
static hasMany= [dataPerson:DataPerson]
}
The left join will mean even when dataPerson does not exist it will attempt to join the (null object)
When iterating if all I wanted was the aspects hanging off of dataPerson then
result?.each { output ->
// if hasMany
println "${output.dataPerson[0].name}"
// if a belongsTo or a direct relation:
println "${output.dataPerson.name}"
}
And to save on doing any of this if you define the actual elements you wish to collect in your HQL then your final iteration will only consist of what it is you asked for exactly and then there is no need to forward walk through the class.
String query="""
select new map(d.name as name,d.surname as surname, d.address as address)
from ClientConfig c
...
You now have objects here no need to expand from result to result.dataSet ....:
result?.each { output ->
println " $output.name $output.surname $output.address "
}

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 }

Object == Object2 when stored in List<T> but not when object in IEnumerable<T> - WHY?

Using ASP MVC5 and EF6.
I had a curious case the other day when I was looking to have different behaviour when a foreach-loop got to the last element.
The loop wouldn't enter if-condition comparing the object with the result from .Last()-method on the collection.
The collection I was iterating over was something like:
public class CollectionClass{
IEnumerable<TestClass1> CollectionA
IEnumerable<TestClass2> CollectionB
}
My code was something like:
DbContext db = new DbContext(); //just for illustration, not actual code
CollectionClass cc = new CollectionClass {
CollectionA = db.TestClasses1,
CollectionB = db.TestClasses2
};
//(TestClasses1 and TestClasses2 are DbSet<T> properties of my DbContext.
foreach(TestClass1 tc1 in cc.CollectionA)
{
if (tc1 == cc.CollectionA.Last()){ //<---NEVER enters in here!!
//doStuff
}
else{
//doOtherStuff
}
}
With the code above, the loop never entered into the if-condition, even for the last element, which one would expect.
But when changed my CollectionClass to:
public class CollectionClass{
List<TestClass1> CollectionA
List<TestClass2> CollectionB
}
and instantiated the CollectionClass-object like this:
CollectionClass cc = new CollectionClass {
CollectionA = db.TestClasses1.ToList(),
CollectionB = db.TestClasses2.ToList()
}; //Added .ToList()
the loop entered into the first if-condition at the last iteration as I expected.
Why this difference? Why did the equals-operator (==) evaluate to TRUE when the object had been stored in a List and FALSE when the object was stored in an IEnumerable?
I know that IEnumerable is an interface -- is that what makes the difference?
I even did an explicit test in the sorts of:
var obj1 = cc.CollectionA.Last();
var obj2 cc.CollectionA.Last();
bool result = obj1 == obj2; //result = FALSE
and the result was FALSE.
I think it's because in first example you get two objects from database. First from iteration and second from call to Last().
In second example all objects are created at the time you assign collections to CollectionA and CollectionB (you call ToList()).
It is because you are not allowed to use Last and LastOrDefault on DbSet objects. Instead you should use OrderByDescending(t=>t.ID).First()

grails PreUpdateEventListener infinite loop

I have PreUpdateEventListener in my application. It looks like:
public boolean onPreUpdate(PreUpdateEvent event) {
if (!needClasses.contains(entity?.class?.name))
return false
def entity = event.entity
boolean rez = false
entity.withSession {org.hibernate.Session session ->
def tryFind = Book.executeQuery("select s.id from ${entity.class.name} s where s.id=? ".toString(), [entity.id])
rez = (tryFind != null && tryFind.size() > 0)
}
return !rez
}
while executing Book.executeQuery it call onPreUpdate again, goes to this line and so on. finally it crash with stack overflow exception by this infinite self calling.
can anybody help me?
Is it possible that the entity is different then an instance of Book ?
Try using findAll() method instead of executeQuery.
Book.findAll("From ${entity.class.name} s where s.id=? ", [entity.id])
//OR this is same as above
def exist = entity.class.get(entity.id)
If the entity can be of different type then Book, instead of calling findAll on the Book class you should call it on proper class.
First try using findAll, I guess it would fix your issue.

Resources