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)
Related
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.
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.
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.
I have a question about GORM and "multiple" hasmany relationships, and I didn't find an answer in my previous searches.
Let's say we have three domains:
class A {
...
static hasMany = [Bs: B]
}
and
class B {
...
static belongsTo = A
static hasMany = [Cs: C]
}
and
class C {
static belongsTo = B
String name
dateCreated date
}
I want to know if it is possible to get a list of objects of the class C, sorted by dateCreated, using an object of the class A (something like C.findAll(...., a: a.id) ) or if I have to use a more complex query ?
Best regards,
Its a little more difficult because you aren't storing a back reference to the parent objects
Something like this - I didn't test it myself
A.executeQuery("select distinct c from A a join a.bs as b join b.cs as c where a = :a", [a: a])
If B has:
static belongsTo = [a:A]
then you can do:
C.withCriteria {
a{
eq('id', <a's id here>)
}
order('dateCreated', 'desc')
}
Here is my domain class:
class Category {
String name
static hasMany = [subCategories: Category]
static belongsTo = [parentCategory: Category]
static mapping = {
subCategories joinTable: false, column: "parent_id"
}
static constraints = {
parentCategory nullable: true
}}
Category is a domain class and has self-reference to both parent and list of children.
Now I want something like this: given a parent category id, I want a list of all sub-categories belong to this id. (NB: not direct children, all the children under the id)
For example, id 1 has children 2 and 3, and 2 has children 4 and 5.
Given I got category id 1 from client, I want a sub categories with id 2,3,4,5
Taken advantage of Groovy, what is the best code to implement that?
Untested code but might get you moving in the right direction. There might be a "groovier" way to do this, but I'm not sure.
def findAllChildren(category, results = []) {
category.subCategories.each { child ->
results << child
findAllChildren(child, results)
}
}
def someOtherMethod() {
def allChildren = []
findAllChildren(parentCategory, allChildren)
}