Find all objects with value in list - grails

I'm introducing myself to the Grails environment (It's awesome). I've been reaping the benefits of dynamically generated methods like the findAllBy* range. However, I've come to a problem and I'm unsure about how to proceed. An hour spent on Google didn't yield all that much for me either.
Problem
I have a class like the following:
class Runner {
static hasMany = [owners: Owner]
}
And in my Owner controller, I wish to find all Runner objects, that contain a given Owner. Effectively, I'm trying to go from the many to the one.
Example
If I have an Owner object, that looks something like
Owner[name="Dave"]
And I have a Runner with something like:
Runner[owners[Owner[name="Dave"], Owner[name="James"]]]
My query should return this Runner object, but it should not return
Runner[owners[Owner[name="Bill"], Owner[name="James"]]]
My attempts
I've attempted to use the inList extension, but after some further research I realised that was designed for the other way around. My code at the moment is as follows:
def runners() {
log.info("Runners")
List<Runner> runners;
Owner owner;
if (params.id) {
log.info("Id = " + params.id);
owner = Owner.get(params.id);
log.info("owner = " + owner.name);
// Grab runners in list thing.
log.info("Number of results = " + runners.size());
}
[results: results, jockeyInstance: jockey]
}

After some research into HQL, I found a more elegant solution that didn't require me to change the Domain classes at all. The query I used was as follows:
runners = Runner.executeQuery("FROM Runner as r WHERE :owner in elements(r.owners)", [owner : ownerInstance]);
Where ownerInstance is the Owner object being used to map to the Runner.

maybe not the answer for the question at hand, but you could also make the runners known to the owners like this
class Runner {
String name
static hasMany = [ owners: Owner ]
static belongsTo = Owner
}
class Owner {
String name
static hasMany = [ runners: Runner ]
}
Owner o1 = new Owner(name: "O1").save()
Owner o2 = new Owner(name: "O2").save()
Owner o3 = new Owner(name: "O3").save()
new Runner(name: "R1").with{
addToOwners(o1)
addToOwners(o2)
save()
}
new Runner(name: "R2").with{
addToOwners(o1)
addToOwners(o3)
save()
}
print o3.runners
results in [runnerowner.Runner : 2]

Is this something you are expecting?
def results = Runner.withCriteria {
owners {
eq 'name', 'Dave'
//idEq params.id //If id of owner is provided
}
}
assuming you have
class Runner {
static hasMany = [owners: Owner]
}
class Owner {
String name
}
Here is a sample you can try.

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.

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 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
}

Better way to discover relationship dynamically when saving a new record? (otherSide fails)

Given this relationship:
class A {
String name
static hasMany = [b:B]
}
class B {
String name
static belongsTo = [a:A]
}
I have an record b that I want to save. I've already discovered via working Grails reflection (omitted in the code example below) that it needs to be an instance of class B. Beyond that, record b only knows:
it has a relation "a"
relation "a"'s key
Since it's a dynamic case, we do not know and must discover:
relation "a" is to an instance of class A (so we can call A.find(a's key))
the "other side" of the relation - class A's perspective - is relation "b" (so we can call .addToB(b))
So how do I save b to the database? Here's how I'm doing it:
class AssocTests extends GrailsUnitTestCase {
protected void setUp() {
super.setUp()
// I don't know this part, but it's in the DB
def a = new A(name:"al")
a.save()
}
void testAssociation() {
// I want to create a new B such that name="bob"
// I also had to discover "class B" using (working) Grails reflection
// but omitted it for this example.
def b = new B(name:"bob")
// ... and the relation is as "given" below
def given = [a:[name:"al"]]
// So I need to call A.find([name:"al"]).addToB(b). But "A" and
// "addToB" are unknown so need to be found via reflection
def gdc = new DefaultGrailsDomainClass(B)
given.each { give ->
def prop = gdc.getPropertyByName(give.key)
if (prop.isAssociation() && !prop.isOwningSide()) {
println "I want to use otherSide, but it's ${prop.otherSide}"
def os = reallyGetOtherSide(B, give)
def object = os.parent.find(
os.parent.newInstance(give.value))
object."${os.method}"(b)
}
}
def bFound = B.findByName("bob")
assertEquals "al", bFound.a.name
}
def reallyGetOtherSide(clazz, relation) {
def parent=clazz.belongsTo[relation.key]
def addTo=parent.hasMany.find { (clazz == it.value) }.key
[parent:parent, method:"addTo${addTo.capitalize()}"]
}
}
...with otherSide returning null, unfortunately. This can't be the best way to do this, can it?
If I understood you correctly, You can refer to these docs here. You can try the following:
`new A(name:"Gatwick")
.addToB(new B(name:"BA3430"))
.addToB(new B(name:"EZ0938"))
.save()`

Grails problem persisting data in join tables for many-to-many relationships

I am having problems persisting domain objects where I have a many-to-many relationship with a join table
class A{
String name
static hasMany = [bs:B]
}
class B{
String surname
static belongsTo=A
static hasMany=[as:A]
}
A a = new A(name:'Test')
B b = new B(surname:'user')
a.addToBs(b)
a.save(flush:true)
Then what I would expect to see is the following
Table A Table AB Table B
id name a_id b_id id surname
1 Test 1 1 1 User
However, the data only persists into table A.
Does anybody know what I am doing wrong ?
thanks
I have found this link which is shows a clear way of mapping many to many relationships
http://chrisbroadfoot.id.au/2008/07/19/many-to-many-relationship-mapping-with-gorm-grails
I still havent been able to get it working the way that I want to at the moment
I tried imitating your code and cascading works for me.
Class A:
package searcher
class A {
String name
static hasMany = [bs:B]
static constraints = {
}
public String toString() {
def s = "Name: $name\n Bs: "
bs.each {
s = "$s $it "
}
return s
}
}
Class B:
package searcher
class B {
String surname
static belongsTo = A
static hasMany = [as:A]
static constraints = {
}
}
Controller Source:
package searcher
class ManyController {
def ab = {
A a = new A(name:'Test')
B b = new B(surname:'user')
a.addToBs(b)
a.save(flush:true)
render A.list()
}
}
Produces output:
[Name: Test Bs: searcher.B : 1 ]
I didn't run into the problem you did, but I did have some initial trouble that was fixed by doing a grails clean. Have you tried a variety of database configurations? I was just using an in memory hsqldb set to create-drop. If you're using a DBMS that I happen to have installed I'll try pointing it to another database and giving it a whirl.

Resources