Grails named query - find by association - grails

I want to create a named query that will find all objects of one class, based on a property (or properties) of child class properties.
I want to be able to find all Bars where Foo.me == "some string"
So, I have this, and it doesn't work:
class Foo {
String me
}
class Bar {
Foo foo
static namedQueries = {
findByFooMe { meStr ->
eq(foo.me, meStr)
}
}
}
What does the correct syntax look like please? Also, how does it change if Bar hasMany Foos, and I want to find all Bars where one of its Foo,me properties is "search string"?
i.e.
class Bar {
static hasMany [foos: Foo]
}

While I wouldn't recommend using findBy as the prefix to a named query, you are close to having the right implementation. Here is an updated version with a new name for the query too.
static namedQueries = {
locateByFooMe { meStr ->
foo {
eq('me', meStr)
}
}
}
If you change your relationship to a collection (One to Many) just make sure the property name foo (in this case) changes to whatever you change it to (foos in your question) and the above query will still continue to work.

Related

grails 2.5.1 removeFrom one-to-many giving strange behavior (not removing)

I'm pretty much certain I'm doing something wrong since this obviously works. Simplified classes:
class Person {
String name
static hasMany = [cats:Cat]
}
class Cat {
String name
Person person
static belongsTo = Person
static constraints = {
person(nullable:false)
}
String toString() {
"${person.name}-${name}"
}
}
Simple stuff, a person has many cats, cats must belong to only a single person.
Now when I do the following in a Service class, I get strange results:
delete(Cat cat) {
Person owner = cat.person
log.debug("Cats before removing ${cat} (id=${cat.id}): ${owner.cats} -- ${owner.cats*.id}")
owner.removeFromCats(cat);
log.debug("Removed from owner ${owner}, owner now has ${owner.cats} -- ${owner.cats*.id}")
log.debug("Cat to delete is now: ${cat} and belongs to... ${cat.person}")
cat.delete(flush:true)
}
And the error is "object would be resaved, blah blah"
org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations)
The weird bit is the debug results, when called to remove cat "Fluffy" who's owned by "Bob":
Cats before removing Bob-Fluffy (id=1356): [Bob-Fluffy] -- [1356]
Removed from owner Bob, owner now has [null-Fluffy] -- [1356]
Cat to delete is now: null-Fluffy and belongs to... null
What's going on that "removeFrom" isn't actually removing the object from the collection? I cleaned and recompiled. Pretty much at a loss as to why I can't delete this object.
I would try to remove the field person as Person person and leave only the belongsTo field like this
class Cat {
String name
static belongsTo = [person:Person]
static constraints = {
person(nullable:false)
}
String toString() {
"${person.name}-${name}"
}
}
It looks like what was happening in my case is that cat.person has getting stale somehow, even though it's the first thing in the method. Calling cat.refresh() didn't work, but calling owner.refresh() after extracting it from the cat.
I would change the domain class as such.
class Person {
String name
static hasMany = [cats:Cat]
}
class Cat {
String name
Person person
// no need to add belongs to property here. it creates a join table that you may not need
static constraints = {
person(nullable:false)
}
String toString() {
"${person.name}-${name}"
}
}
In the service class
delete(Cat cat) {
cat.delete(flush:true)
}
Once you make the domain changes, start with a fresh database since the schema will change.
I think that should solve your problem.

propertyMissing doesn't work in Criteria?

So I've got a couple of classes with the following relationship:
class Foo {
Bar bar
/* ... other fields ... */
}
class Bar {
String name
}
In class Foo I've got a couple of named queries:
static namedQueries = {
userFoos { user ->
/* ... get Foos for this user ... */
}
limitFoos { colname, dir ->
order(colname, dir)
}
...which I can then chain together in a controller:
def foos = Foo.userFoos(currentUser).limit(colname, dir)
Pretty straightforward so far. The problem is when I try to sort on bar; I get the error:
could not resolve property: bar.name of: package.Foo.
Now, I also got this error when the queries were Criteria that were declared in the controller. So, I went and wrote a propertyMissing handler for Foo:
def propertyMissing(String name) {
if (name.contains(".")) {
def (String propertyname, String subproperty) = name.tokenize(".")
if (this.hasProperty(propertyname) && this."$propertyname".hasProperty(subproperty)) {
return this."$propertyname"."$subproperty"
}
}
}
I don't know if this is really the best way to do it, but it did work! However, now that I've moved the query into the class as a named query, propertyMissing doesn't appear to work anymore! Is this use not supported, or am I just missing something here?
EDIT
So I tried moving the Criteria back into the controller and sure enough, the sub-property sort did not work there either! So I guess Criteria just don't support propertyMissing at all :/
To answer dmahapatro's question, I am using jQuery DataTables to present the information. Clicking on a column header does an AJAX call to a controller action with parameters to indicate which column to sort on and in which direction. Once I determine the column name, I call the named queries like so:
def foosFilteredLimited = params.sSearch ?
Foo.userFoos(currentUser).filterFoos(params.sSearch).limitFoos(offset, max, colName, sortDir).list()
: Foo.userFoos(currentUser).limitFoos(offset, max, colName, sortDir).list()
(filterFoos takes a search string and narrows the results of userFoos.)
Try modifying limitFoos namedQuery as below and it should work. There is a caveat to it though. We cannot use bar.baz.name if required. ;)
limitFoos { column, ord ->
def colStrs = column.tokenize(/./).toList()
if( colStrs?.size() > 1 ) {
"${colStrs[0]}" {
order( "${colStrs[1]}", ord )
}
} else {
order(column, ord)
}
}

GORM, Envers and #NotAudited relationships or adding annotations to hasMany-relation

I am using hibernate envers with Grails, defining some entities with #Audited to let them audited by the API. Some entities should not be audited, so I am defining #Audited(... NOT_AUDITED) which runs also smoothly.
But this time, I have a relationship defined following
static hasMany = { foos : Foo }
Foo is also declared as NOT_Audited at class level, but envers is ignoring this and searching for an AUDIT table. However, I have seen that it might be necessary to add the annotation #NotAudited to the relationship to inform envers that the type should not be audited.
So, I have tried:
static hasMany = {#NotAudited foos : Foo }
// Or desperately:
#NotAudited
static hasMany = { foos : Foo }
Either it seems that my approach is false or that GORM is ignoring the annotation.
Does anyone have experience with it where it is not enough to define "Not_Audited" at class level like
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
class Foo{
...
}
#Audited
class Bar{
static hasMany = { foos : Foo }
...
}
EDIT: Maybe good to mention that
static hasMany = {#NotAudited foos : Foo }
runs into compilation error. So, maybe my problem is just how to add the annotation to the relationship.
I don't know if you found your answer, but you need to overload the getter, and put the annotation on it :
#NotAudited
def getFoos() {foos}
At least, it works for direct associations...

One-to-Many With Composite Keys and Different Column Names in Grails

This is a syntax question. I want a one-to-many relationship between Foo -> Bar (simplified here):
class Foo {
String fooPK1, fooPK2
static mapping = {
id composite: ["fooPK1", "fooPK2"]
}
static hasMany = [bars: Bar]
}
class Bar {
String fooPK1, dumbNameForFooPK2, barPK1, barPK2
Foo myFoo
static mapping = {
id composite: ["barPK1", "barPK2"]
columns {
myFoo[:] {
column name: "FOO_PK_1"
column name: "?????????????"
}
}
}
}
In this case, obviously Foo.fooPK1 maps to Bar.fooPK1, but i need Foo.fooPK2 to map to Bar.dumbNameForFooPK2. Hopefully this makes sense.
My problem is I have no idea what the syntax is supposed to be (or if there's a better way to do this!) and from what I could find, the grails documentation wasn't really helpful.
You need to rename the foreign key columns declaration inside Bar, wright?
class Bar {
Foo myFoo
static mapping = {
columns {
myFoo {
//declare them in the order of your id composite.
column name: "foo_pk_1"
column name: "dumb_name_for_foo_pk_2"
}
}
}
}

Grails GORM Query with Multiple Objects?

I am trying to write a query in Grails to return a set of results from a domain class, but within those return the relevant results of a separate class whom have the parentId of the main class.
def query = Cars.where {
(colour == 'red')
}
And then within each list item include the set of parts relating to that CAR ID (as an example of what I'm trying to achieve, I know the code is incorrect though....
query.each{
this car. add(Parts.whereCarID{it.id})
}
If you define your domain model properly, you should get it without a criteria involved.
As far as I understand you need to add static hasMany = [parts: Parts] in your Cars domain class, and static belongsTo = [car:Cars] in your Parts class.
So for example, here how it might look:
class Cars {
string colour
static hasMany = [parts:Parts]
// ... rest of your properties
}
class Parts {
static belongsTo = [car:Cars]
// ... rest of your properties
}
And to get your result just do this:
def cars = Cars.findAllByColour('red')
Then you can do:
cars.each { car->
println car.parts // <-- all the parts for each car is here
}

Resources