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
}
Related
I need to compare several domain class objects while they are still unsaved, however, I always keep getting a false result from the comparison. Turns out even the following comparison will return false:
new DomainClass().equals(new DomainClass())
Since both are brand new objects they should both have identical data and should be equal to each other. Unfortunately the equals method (or the == operator) returns false. Is there another correct way of performing this comparison?
Your code same with this:
a = new DomainClass();
b = new DomainClass();
a.equals(b)
So clearly the test must return false as far as a and b are not referencing same object.
If you want value based comparing:
Iterate over the fields and compare them one by one
Or check here for a more formal way of doing it.
you can use 'spaceship operator' (<=>) which work like compareTo()
or you can override equals() method in your DomainClass that make able to use this code
new DomainClass().equals(new DomainClass())
to override equals() you can use #EqualsAndHashCode annotation
this annotation automatically generate equals() and hashcode() methods
So, you class will look like this:
#EqualsAndHashCode
class DomainClass(){
String field1
String filed2
etc
}
and your generated equals method will look like this:
public boolean equals(java.lang.Object other)
if (other == null) return false
if (this.is(other)) return true
if (!(other instanceof DomainClass)) return false
if (!other.canEqual(this)) return false
if (field1 != other.field1) return false
if (field2 != other.field2) return false
// etc
return true
}
For more details look at this http://groovy.codehaus.org/api/groovy/transform/EqualsAndHashCode.html
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 }
so I have a form with several fields which are criteria for searching in a database.
I want to formulate a query using LINQ like so:
var Coll = (from obj in table where value1 = criteria1 && value2 = criteria2...)
and so on.
My problem is, I don't want to write it using If statements to check if every field has been filled in, nor do I want to make separate methods for the various search cases (criteria 1 and criteria 5 input; criteria 2 and criteria 3 input ... etc.)
So my question is: How can I achieve this without writing an excessive amount of code? If I just write in the query with comparison, will it screw up the return values if the user inputs only SOME values?
Thanks for your help.
Yes, it will screw up.
I would go with the ifs, I don't see what's wrong with them:
var query = table;
if(criteria1 != null)
query = query.Where(x => x.Value1 == criteria1);
if(criteria2 != null)
query = query.Where(x => x.Value2 == criteria2);
If you have a lot of criteria you could use expressions, a dictionary and a loop to cut down on the repetitive code.
In an ASP.NET MVC app, chances are your user input is coming from a form which is being POSTed to your server. In that case, you can make use of strongly-typed views, using a viewmodel with [Required] on the criteria that MUST be provided. Then you wrap your method in if (ModelState.IsValid) { ... } and you've excluded all the cases where the user hasn't given you something they need.
Beyond that, if you can collect your criteria into a list, you can filter it. So, you could do something like this:
filterBy = userValues.Where(v => v != null);
var Coll = (from obj in table where filterBy.Contains(value1) select obj);
You can make this more complex by having a Dictionary (or Lookup for non-unique keys) that contains a user-entered value along with some label (an enum, perhaps) that tells you which field they're filtering by, and then you can group them by that label to separate out the filters for each field, and then filter as above. You could even have a custom SearchFilter object that contains other info, so you can have filters with AND, NOT and OR conditions...
Failing that, you can remember that until you trigger evaluation of an IQueryable, it doesn't hit the database, so you can just do this:
var Coll = (from obj in table where value1 == requiredCriteria select obj);
if(criteria1 != null)
{
query = query.Where(x => x.Value1 == criteria1);
}
//etc...
if(criteria5 != null)
{
query = query.Where(x => x.Value5 == criteria5);
}
return query.ToList();
That first line applies any criteria that MUST be there; if there aren't any mandatory ones then it could just be var Coll = table;.
That will add any criteria that are provided will be applied, any that aren't will be ignored, you catch all the possible combinations, and only one query is made at the end when you .ToList() it.
As I understand of your question you want to centralize multiple if for the sake of readability; if I were right the following would be one of some possible solutions
Func<object, object, bool> CheckValueWithAnd = (x, y) => x == null ? true : x==y;
var query = from obj in table
where CheckValue(obj.value1, criteria1) &&
CheckValue(obj.value2, criteria2) &&
...
select obj;
It ls flexible because in different situations or scenarios you can change the function in the way that fulfill your expectation and you do not need to have multiple if.
If you want to use OR operand in your expression you need to have second function
Func<object, object, bool> CheckValueWithOr = (x, y) => x == null ? false : x==y;
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.
I have a command object that captures a feedback form with 3 textareas.
class FeedbackCommand {
String textarea1
String textarea2
String textarea3
String username
static constraints = {
textarea1(nullable:true, blank:true)
textarea2(nullable:true, blank:true)
textarea3(nullable:true, blank:true)
username(nullable:false, blank:false)
}
}
I'd like to ensure that at least ONE of the textareas is filled out.
I came up with adding a fake flag field as a 'constraint' field, and then doing a bunch of object checks in the custom validator for that field. If after looking around in myself and i dont find what I want, I throw an error.
Right now, I'm doing this:
class FeedbackCommand {
String textarea1
String textarea2
String textarea3
boolean atLeastOne = true
String username
static constraints = {
textarea1(nullable:true, blank:true)
textarea2(nullable:true, blank:true)
textarea3(nullable:true, blank:true)
atLeastOne(validator: { boolean b, FeedbackCommand form, Errors err ->
if (b) {
if ( (form.textarea1==null || form.textarea1?.isAllWhitespace()) &&
(form.textarea2==null || form.textarea2?.isAllWhitespace()) &&
(form.textarea3==null || form.textarea3?.isAllWhitespace()))
{
// They havent provided ANY feedback. Throw an error
err.rejectValue("atLeastOne", "no.feedback")
return false
}
}
return true
})
username(nullable:false, blank:false)
}
}
Is there a better way to
validate a related/group of fields (at least one can't be blank, 2 should have values, etc)?
a groovier way to express "at least one shouldnt be null/blank" rather than my gross if-statement block?
Thanks
The Extended Validation plugin also adds support for instance validators, which allow to define constraints over several field without defining an artificial flag field or without repeating the validator for each field involved.
validate a related/group of fields (at least one can't be blank, 2 should have values, etc)?
Try this:
if ( (form.textarea1?.trim() ? 1 : 0) +
(form.textarea2?.trim() ? 1 : 0) +
(form.textarea3?.trim() ? 1 : 0) < 2) {
err.rejectValue("atLeastTwo", "no.feedback")
return false
}
a groovier way to express "at least one shouldnt be null/blank" rather than my gross if-statement block?
This is slightly Groovier...
if (!( (form.textarea1?.trim() ?: 0) ||
(form.textarea2?.trim() ?: 0) ||
(form.textarea3?.trim() ?: 0) )) {
err.rejectValue("atLeastOne", "no.feedback")
return false
}
WRT validating a group of fields, you could assign the validator closure to one of the fields. You don't need any extra/ficticious field.
If it's going to be used often, create a plugin
http://www.zorched.net/2008/01/25/build-a-custom-validator-in-grails-with-a-plugin/
or use a plugin for constraints
http://grails.org/plugin/constraints
About grooviness I'm not an expert. But the safe navigator operator ?. makes unnecessary to ask for null
if ( form.textarea1?.isAllWhitespace() &&
form.textarea2?.isAllWhitespace() &&
form.textarea3?.isAllWhitespace() )
{
// They havent provided ANY feedback. Throw an error
err.rejectValue("atLeastOne", "no.feedback")
return false
}
You can use the min-criteria plugin for that.
http://www.grails.org/plugin/min-criteria