Grails - get domain relationship id without fetching the whole object - grails

I have, for example, the following domain objects:
class A {
B b
static constraints = {
b nullable: true
}
}
class B {
}
Given instance of A, I would like to fetch only the id of B.
I tried the following, but received null every time:
def id = a.bId
Is it possible to fetch the id of b without doing a.b.id ?

You will need to enhance your domain to use GORM based mapping hints (given to Hibernate) to accomplish this.
Your domain could look something like this:
class A {
static hasOne = [b: B]
}
class B {
// stuff
}
Using the hasOne will allow Hibernate to manage the association and thus allows you to use the a.bId notation.
Hope this helps.

Related

Grails/Gorm: Inheritance and foreign keys

Given Domain Classes like these:
class A { // in reality this is a basic User class that is required in multiple projects
}
class B extends A { // in reality B is a "patient"-kind of user.
static hasMany = [c: C]
}
// c/d is stuff like "MedicationPrescription", so basically data only relevant to the patient. However the system needs to realize that Patients are Users, as the User base class is used for spring security logins and in general has a lot of the basic data a person just has. (Name, etc.)
class C {
static belongsTo = [b: B, a: A, d: D]
}
class D {
}
I get this error:
org.hibernate.MappingException: Foreign key (FK_pwu2w72ul5a5213husrv3onr3:c [])) must have same number of columns as the referenced primary key (a [id])
at org.hibernate.mapping.ForeignKey.alignColumns(ForeignKey.java:110)
at org.hibernate.mapping.ForeignKey.alignColumns(ForeignKey.java:93)
at org.hibernate.cfg.Configuration.secondPassCompileForeignKeys(Configuration.java:1818)
at org.hibernate.cfg.Configuration.originalSecondPassCompile(Configuration.java:1741)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1426)
at org.grails.orm.hibernate.cfg.HibernateMappingContextConfiguration.secondPassCompile(HibernateMappingContextConfiguration.java:287)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1846)
at org.grails.orm.hibernate.cfg.HibernateMappingContextConfiguration.buildSessionFactory(HibernateMappingContextConfiguration.java:196)
at org.grails.orm.hibernate.HibernateMappingContextSessionFactoryBean.doBuildSessionFactory(HibernateMappingContextSessionFactoryBean.java:476)
at org.grails.orm.hibernate.HibernateMappingContextSessionFactoryBean.buildSessionFactory(HibernateMappingContextSessionFactoryBean.java:470)
at org.grails.orm.hibernate.HibernateMappingContextSessionFactoryBean.afterPropertiesSet(HibernateMappingContextSessionFactoryBean.java:93)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
... 41 common frames omitted
The error goes away if I remove the inheritance between A and B, but I havee this constellation in my Domain. I don't understand why Gorm does what it does, from the error message it seems to think the list of attributes in the foreign key is empty?
Additionally I cannot even mention classes B, C or D in class A, as class A is part of a plugin that just doesn't know about those classes.
EDIT:
I might just do away with the inheritance and use composition instead like this:
class B {
A a
static hasMany = [c: C]
}
That doesn't blow up on startup at least, but still: Why?
You can take care of your domain class constellation like this:
class User { }
class Patient extends User {
static hasMany = [prescriptions: MedicationPrescription, stuff: OtherStuff]
}
class MedicationPrescription {
static belongsTo = [patient: Patient]
}
class OtherStuff {
static belongsTo = [patient: Patient]
}
This creates a bi-directional one-to-many association between Patient and MedicationPrescription and also between Patient and OtherStuff. Notice that each belongsTo has a corresponding hasMany.
As you've already discovered, you can also use composition.

Grails hasMany delete behavior

I have 2 domain classes
class A {
static hasMany = [ b : B ]
}
class B {
static belongsTo = A
}
I would like to keep the cascading saves, so when I save A, it updates the B's, but when I do a delete of A, I would like it to fail if any B's exist that are associated with that A. So you would have to explicitly delete all of the B's first.
I'm not sure the easiest way to do this in Grails. I could put a check in A before I delete it to verify that there are no B's - simple enough. But is there a way to control this through cascading or relationship behaviors so I don't have to put the logic in there?
Specify the cascade behavior for the collection
class A {
static hasMany = [ b : B ]
static mapping = {
b cascade: 'save-update'
}
}
It will cascade save and update but not delete.

How can I get dateCreated in Has-Many Relation in Grails?

I have the following domain classes:
class A {
hasMany = [bs : B]
}
class B { }
Note that B has no backward relation to a. GORM creates a join table in my MYSQL database a_b. This table has two columns the id of a and the id of b.
How can I get a dateCreatedin the join table?
Create a model of the join table yourself and add whatever properties you want on it. Simple, and done.
For example:
class A {
static hasMany = [bs: JoinB]
}
class JoinB {
static belongsTo = [a: A]
B b
Date dateCreated
static mapping = {
autoTimestamp true // default, but I like to be explicit about it.
}
}
class B {
String whatever
}
(Careful of typos etc. I just did that off the top of my head)

Grails search owned objects by properties

I am trying to find the proper syntax for a query that I know has got to be very common but couldn't find a code example for.
class ObjA {
...
static hasMany = [b:ObjB]
}
if a is an instance of ObjA, I want to perform a query like:
a.b.findAllBsSuchThat(b.someproperty = somevalue)
In order to avoid (N+1) queries for lazy associations per a, you can use a criteria as:
ObjA.withCriteria {
b {
eq 'someProperty', someValue
}
}
or where queries:
ObjA.where { b.someProperty == somevalue }.list()
If you use something like a.b.findAllBsSuchThat(b.someproperty = somevalue) then you would be getting all b's for a and then filtering on the result. This will affect the performance and will unnecessary.

Criteria on a one-to-many relation

My domain contains a one-to-many relationship like this:
class A {
B b
}
class B {
String name
}
I want to create a criteria query on A which will look for A to have the B object with the given name. It may return multiple entries. So... compare a given string with the "name" field from B and return the list of entries of type A for which B matches the name.
Thx!
Unless I am missing something that should be pretty easy:
def instanceList = A.withCriteria {
b {
eq('name','whatever')
}
}

Resources