Why is Grails / Gorm looking for back reference column in DB? - grails

as part of an upgrade from 2.4 to Grails 5, I've encountered an oddity where when I attempt to access a particular field in a domain, I get a SQL exception because the back reference _id column is not found.
My model is as such:
class Parent {
Child firstChild
Child secondChild
}
class Child {
static belongsTo = [parent:Parent]
}
My understanding is there will be a parent property added to the Child class, but no back referencing column will be created in the table unless I add a hasOne declaration to the Parent class. Which is what I want, and what used to work. This also works if there is only one Child, but the problem starts when I add the secondChild.
However when I have an instance of a Parent, e.g. Child childInstance and I access the parent property, then it's firing a SQL Syntax exception Unknown column 'parent_id' in 'field list'
Since Grails 2.4 is there something different we need to do to correctly handle this relationship and not require any parent_id in the child table
Thanks.

Related

Is there a way to fetch a GORM entity with hasOne child lazily?

I have a simple one-to-one relation between two Grails entitites like this:
class Parent {
static hasOne = [child: Child]
}
class Child {
Parent parent
}
The problem is that when loading the parent entity (e.g. using def parent = Parent.first()), the child is selected from the database simultaneously with a second query as can be seen in the hibernate debug log, although according to the documentation single-ended associations should be fetched lazily by default. Also using the lazy: true mapping configuration from the mentioned docs apparently doesn't change anything.
The situation is the same when using static belongsTo = [parent: Parent] in the child instead.
This issue (currently open) describes the same behavior.
So is there any way to stop the child association to be fetched?
Optimally, I imagine it should be either fetched using a single select with join or not selected at all (or upon first access of the child), preferrably controlled by a switch or using a fetch join in a HQL query.
Optimally, I imagine it should be either fetched using a single select
with join or not selected at all (or upon first access of the child),
preferrably controlled by a switch or using a fetch join in a HQL
query.
It can be made to be fetched with a single select.
The issue at https://github.com/grails/gorm-hibernate5/issues/136 links to the sample project at https://github.com/alanbino/gorm-hasone. I forked that to https://github.com/jeffbrown/gorm-hasone and made changes.
The commit at https://github.com/jeffbrown/gorm-hasone/commit/32cb943cbc27deb5ebf164aa1461b3956285fe1d demonstrates how to get the data retrieved in a single select. That commits configures the join...
static mapping = {
table 'a_parent'
id generator:'assigned'
aChild fetch: 'join'
}
The subsequent commit at https://github.com/jeffbrown/gorm-hasone/commit/575ae2152767ded30686cb2e3daa70519f03c8ba isn't really related to the issue here, but eliminates a number of complexities that don't relate to the issue and eliminating those makes it easier to evaluate the code. Ignore that if that is a distraction.

Grails: Simple hasMany relation create more tables than necessary

Hi I have a simple problem.
My domain class is like this:
class Example {
long seq
hasMany = [example_array: ExampleData]
long count
}
class ExampleData {
String type
long description
static belongsTo = Example
static constraints = {
}
}
This results in 3 tables, like a many to many relation.
Why is this?
Thanks
The reason for the extra table is that you've modeled the relation only in one direction - an Example can access its ExampleData instances via the example_array Set that's added to your class bytecode because of the hasMany property, but an ExampleData instance has no way to reference its owning Example.
You added a belongsTo property, but only specified the class name. That's sufficient to configure ownership, cascaded deletes, etc. but doesn't provide a property in the class to access the Example instance.
If you change it to the other supported syntax it will work as you expected:
static belongsTo = [example: Example]
Here example will end up being the name of an Example property (and you can change it and/or example_array to any valid property name), which is basically the same as declaring
Example example
Now that both sides can access the other, the relationship is bidirectional and you no longer need the third table. That's because a 1-many is typically implemented using a foreign key in the child table, in this case in the table for ExampleData that points to the table for Example. That wasn't possible without a property in the class to wire up to that column, so the join table was necessary.
I believe that you have to map the BelongsTo, like this:
static belongsTo = [example:Example]
Hope it helps :)
From the definition of hasMany Grails will, by default, map this kind of relationship with a join table.That join table is the 3rd table you mentioned.No need to worry about that.
Well the one-to-many relationship is constructed by having additional table (i.e. Example_ExampleData) containing two columns each id fields from tables of the entities forming the relationship(i.e. Example and ExampleData).
The newly added table is child to parent tables – Example and ExampleData.
So in your case when you run your application the 3rd table gets created by Grails by default as your table relationship falls under the one-to-many relationship.

Issue on Grails GORM domain classes with "soft" joins

I have mapped two tables on Domain classes, say:
Parent table that hasMany of the table Child.
Child table that belongsTo a table Parent.
I want point out that there is no specific foreign keys explicitly declared on the database, rather it is declared on the GORM's mapping. But here's the catch: There are special types of Child that are orphans- that is, doesn't have their Parent table counterparts. Everytime I access these orphans via a valid Child.findById(), an error shows:
Message: No row with the given identifier exists
that is not present when accessing a non-orphan Child. I had marshalled these Domain tables already in such a way that everytime a Child is parsed as JSON, it will have a property called parents which is an array of Parent and the other way around. It is already working- except for these orphans' case.
How should I fixed this? Should I remove their GORM join, since they are not actually joint on the database side?
I'm assuming you have domain classes that look like this:
class Parent {
static hasMany = [children: Child]
}
class Child {
static belongsTo = [parent: Parent]
}
That's a bi-directional one-to-many association. GORM expects the child table to contain a foreign key to the parent, and the child can only exist if it has a parent.
One way to allow orphan children is do to as you suggested: remove the gorm associations. Another way is to remove the belongsTo to create a uni-directional association. That way a child can exist without a parent.

Hibernate hasMany / belongsTo structure

I am currently running Grails 2.3.3 with 'in memory' H2 database.
Where does H2 keep the Ids of all the children instances of a "hasMany"/"belongTo" condition.
I believe there must an additional storage place over and above the column that stores the parent Id in the child domain model.
I assume this because I need to run a removeFrom command prior to deleting a child directly from its domain model.
For example:
A parent domain model has a hasMany construct:
static hasMany = [ videoCatDataHM: VideoCatDataShr]
the child domain has a complimentary 'belongsTo' construct:
static belongsTo = [ vidCatAdminBT: VideoCatAdminShr]
There is a column in the child domain model called VID_CAT_ADMIN_BT_ID that correctly stores the Ids of the parent.
Prior to running a delete on a child instance I have to run this removeFrom command:
vidCatAdminId.removeFromVideoCatDataHM(videoCatDataShrInstance)
This suggests that the parent holds additional records of all the hasMany children linked to it separately from the Ids held in the child DM.
As suggested I have added Hibernate logging to this application - here are the non-select (that is DM changing ) logs are:
Hibernate: update video_cat_admin_shr set version=?, description=?, name=?, organbt_id=? where id=? and version=?
Hibernate: delete from video_cat_data_shr where id=? and version=?
The update is updating the parent instance (presumably via the removeFrom call ) and the delete is deleting the child instance. Viewing the parent instance via the dbconsole before and after the delete shows that the only change to the parent instance is that the version number of the instance is incremented by one.
Note that this has nothing to do with H2, it would be the same in any relational database managed by the Hibernate GORM implementation.
In this case you've defined a bidirectional one-to-many, so you've answered your question - it's the column in the child table corresponding to the "owner" property, in this case VID_CAT_ADMIN_BT_ID from VideoCatDataShr.vidCatAdminBT.
But there isn't any collection of child ids stored in the database, but rather the ids are queried as needed, essentially
select VID_CAT_ADMIN_BT_ID from video_cat_data_shr where id=?
where the ? is the id of the owning VideoCatAdminShr instance. This query will find all child records linked back to the parent using this foreign key. Turn on SQL logging to see the actual queries used.

Correct method for adding master/child entity in breeze?

Each time I think I have it nailed, it rears its head again!
So simply if there's a master table with navigation property to a collection of children and I use "createEntity" to create a new empty version of the entity I am able to see the navigation property in the entity returned, but I am unable to access/set any properties. I suspect this is because the parent key does not yet exist in the child entity?
To clarify. I can put in a breakpoint at the point where the new entity is returned and if I inspect the master() entity I can see the children property right there. If I then try and do:
master().children.childProperty("this is a new value")
...then I simply get "object function observable()..." (then loads of code from knockout I think) and ending "has no method 'childProperty'"
I think I've tried every combination of parentheses known to man and I get slightly different errors but nothing works. Do I need to have a [0] in there somewhere as "children" is effectively an array?
Added info for clarification.
As detailed in comments below, retrieving an existing entity with "expand" specified in the query for eager loading returns a master entity with a related child entity, properties of which I can set with the method I was trying to for the "new" example above which doesn't work. The specified length of the "children" collection when I return an existing master/child is 1, when I initialize a new master/child the array length is zero.
This isn't, I suppose, a traditional master/child relationship - it's more an associated entity than a child. To explain, "master" will always have one child record - think of it as master being a bottle and child being the related record that determines the colour of the bottle, the contents and the label details on the bottle. There will only ever be one bottle but there could be dozens of variations of colour, content and label.
When I retrieve an existing master record, I also specify the specific child I want so in this page I will only ever retrieve one master and one child record as I'm editing the specific variation and may want to change the label text.
In another page, I list all the variations for a bottle, so there I retrieve a master and all the associated children in a classic "one to many" example.
The model is:
Public Class bMaster
Public Property ID() As Integer
...other properties
Public Overridable Property bChildren() As ICollection(Of bChild)
End Class
Public Class bChild
Public Property ID() As Integer
Public Property bMasterID() As Integer
...other properties
Public Overridable Property bMaster() As bMaster
End Class
Carl - Kick yourself. You are so close that it hurts to write this for you. If children is a collection you can't simply set a value for each one of them like that. Since they are an array you must select one of them to set a value on.
var child = master().children()[0]; // get the first child
child.childProperty(someValue);
This would also work this way -
ko.utils.arrayForEach(master().children(), function (child) {
child.childProperty(someValue);
});
Which would loop through your array and set the value for each of the entities in the collection.
Edit
If it is a new entity then it doesn't yet have a child entity. If there is always only going to be one child entity of the parent, I am not sure why you are using a collection instead of a complex type or something. You need to create a parent and then create a child on that parent as well -
var parentEntity = manager.createEntity('Parent');
var childEntity = manager.createEntity('Child');
childEntity.parent(parentEntity);
return childEntity;
Then if you wanted to set a property on a parent's child you would do so as I mentioned above -
var child = master().children()[0]; // get the first child
child.childProperty(someValue);
or you could still use
master().children()[0].childProperty(someValue);
Last, if you created the relationship properly (one to one instead of one to many) you could use this -
master().children().childProperty(someValue);

Resources