Coldfusion - ORM removing child objects - orm

I'm trying to nail down the specifics of removing a child in an one-to-many relationship in CF using ORM. I've posted a small test app here:
https://github.com/pnahtanoj/cfrelationship
Regarding the removeChildren() function on ln47 of create.cfm - if I dump the parent object before and after, I see that the children have been removed. However, they are still in the DB after the close of the transaction. Not sure what I'm missing.
Using CF10, MySql 5.something...

Because you set inverse to true on the many side, that means only the child side is tracked by Hibernate.
You can set all the child's parent to null.
public void function removeChildren() {
transaction {
var children = getChilds();
for (var c in children)
c.setParent( javacast('null','') );
}
arrayClear(variables.childs);
}

Related

Any way in Grails 3 for hasOne to do a lazy fetch?

Grails 3.2.5. Is see from my sql dump that the hasOne relationship does an eager fetch. This used to be the case back in prior versions of Grails, and the behavior could not be overridden. Is this still the case? What is the recommended model for a 1:1 relationship where we want a lazy fetch on the dependent object?
A little background. My "Comment" object has a one-to-one relationship with a "CommentText" object, where the text object holds Oracle clob text - some of it large. I only wanted to get the text when explicitly required to do so. The fk was in the dependent database text object, hence the "hasOne". Fortunately I was able to move the fk to the owner side of the association via an embedded domain object and update the db schema.
Throughout, I was unable to get lazy loading of the hasOne dependent object. Tried fetch: 'lazy'; fetchMode: 'lazy, and other variations of things. I needed a full domain class association because of "find" actions that needed to traverse the association.
I would still prefer the hasOne approach, if loading were indeed lazy.
Old question, but I just encountered the same problem so I'll answer for later reference.
Basically, it is impossible to lazy-fetch a hasOne property in Grails 3 (tested with 3.3.11, assuming Hibernate). But there are some workarounds.
The immediate lazy-fetch N+1 problem
As soon as you put hasOne: [child: Child] on the parent class, GORM will force you to make the relationship into a bidirectional one-to-one, and it will put the foreign key on the child table.
When you then fetch entities of the parent, it will immediately fetch all of the child entities as well, but it will do a query for every child (N+1 problem).
So a statement like this
Parent.list(max: 10)
will issue one query to get the 10 parents, and then do a query where parent_id = ? for each of the 10 children.
Even if you put fetch: 'lazy' and batchSize: 10 on the mapping of the child in Parent.groovy, the behavior is the same.
Workaround 1: One-directional with FK on the parent table
This is the solution you mention in your post. If you don't need to access the parent from the child side, you can make the relationship one-directional, which will put the FK on the parent table.
Now when fetching the Parent entity it will fetch the child_id from the parent table automatically, but keep the child property as a Hibernate proxy.
The child entity behind the proxy will correctly only be fetched once you access it. The batchSize mapping seems to be ignored here though, so when you actually start accessing the .child entities it will again issue one query per Parent.
Workaround 2: One-to-many and just access the first element
If you really want to keep the FK on the child table and also have lazy loading, you can use this hackaround.
On the Parent.groovy you could specify it like this
static hasMany = [children: Child]
static transients = ['child']
Child getChild() {
children ? children.first() : null
}
static mapping = {
children batchSize: 100
}
Now when you fetch the Parent entities it will correctly ignore the child property, and if you e.g. loop through a list of Parent and access the .child on each, it will only issue one single query for batchSize Parents.
So code like this:
def parents = Parent.list(max: 10)
parents.each {
log.info it.child.subProperty
}
will do the first query to get the 10 parents, and then one single query to lazily batch-fetch the children for up to batchSize parents. With Sql logging enabled it should look something like this:
select child0_.parent_id, child0_.id, ... from child child0_ where child0_.parent_id in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Workaround 3: The eager-fetch non-workaround
If your application code almost always uses the child property, then one option is to give up on lazy fetching and just specify child fetch: 'join' in Parent.groovy.
This will eliminate the N+1 lazy fetching problem, but as a downside Hibernate will now LEFT JOIN the child table and select all it's properties every time you request the Parent entity, even if you never touch the child property.
Workaround 4: Replace hasOne with mapping column: 'id'
class Face {
Nose nose // due to mapping, column 'nose_id' is not required
static mapping = {
nose column: 'id', insertable: false, updateable: false
}
}
class Nose {
static belongsTo = [face: Face] // due to mapping, column 'face_id' is not required
static mapping = {
// use the parent object's ID as this ID
// optional, but clean
id generator: 'foreign', params: [property: 'face']
// reference to the parent object so we don't need an extra column
face column: 'id', insertable: false, updateable: false
}
}

cached collection not being invalidated by Nhibernate

I have two objects - ContentPage, which has a collection of ChildLinks.
ContentPage
-----------
ID
Title
ChildLink
----------
ID
ParentPageID [ContentPage]
ChildPageID [ContentPage]
Priority
The ContentPage.ChildLinks property utilises the 2nd level cache. I am using Fluent NH to configure Nhibernate, and using Nhibernate 3.1. Cache is set as 'Read-Write' both for the collection, and the 'ChildLink' class.
I've noticed that whenever I delete a ChildLink, the collection cache is not being invalidated. Thus, when I call the ContentPage.ChildLinks, I get an error:
no row with the given identifier exists
I've turned off the cache, and it works well. Shouldn't the cache be automatically invalidated? I am using SysCache as the cache provider, and MySQL as the database.
Thanks in advance!
I had the same problem and I can across the following article which solved my problem:
Inverse Mapped Collections and NHibernate's Second-Level Cache
Basically if you have mapped your collections as inverse, when you delete the child item you also have to make sure to explicitly remove it from the parent collection or the cache state will be invalid after you delete the child. The first thing to check is if the relationship really needs to be inverse.
Assuming inverse is necessary or desired, and using your example:
Instead of only something like:
Session.Delete(ChildLink);
You have to do:
ContentPage.ChildLinks.Remove(ChildLink);
ChildLink.ParentPage = null;
Session.Delete(ChildLink);
You also might need to explicitly save your ContentPage object at this point as well, it depends on your Session flush settings.
I use methods on my entities for managing such inverse relationships, for example:
public ChildLink
{
public ContentPage ParentPage {get;set;}
public void AddToPage(ContentPage addTo)
{
addTo.ChildLinks.Add(this);
this.ParentPage = addTo;
}
public void RemoveFromPage()
{
ParentPage.ChildLinks.Remove(this);
this.ParentPage = null;
}
}
And then when deleting a child object:
ChildLink.RemoveFromPage();
Session.Delete(ChildLink);

NHibernate: Avoiding complete in-memory collections when working with child collections via aggregate root

Considering the simplified class below, lets assume:
that the parent can have a relatively large amount of children (e.g. 1000)
the child collection is lazy loaded
we have loaded one parent via it's Id from a standard Get method of a ParentRepository, and are now going to read the OldestChild property
class Parent
{
public IList<Child> Children { get; set; }
public Child OldestChild
{
get { return Children.OrderByDescending(c => c.Age).FirstOrDefault();
}
}
When using NHibernate and Repositories, is there some best practice approach to satisfy both:
a) Should select oldest child through the aggregate root (Parent) - [ie. without querying the children table independently via e.g. a ChildRepository using the Parent Id]
b) Should avoid loading the whole child collection into memory (ideally the oldest child query should be processed by the DB)
This seems something that should be both possible and easy, but I don't see an obvious way of achieving it. Probably I am missing something?
I'm using NHibernate 2.1, so a solution for that would be great, although will be upgrading to 3 soon.
I would create a specialized method on your repository, which returns the oldest child of a given parent.
You could map OldestChild using a Formula. Take a look at this to map a class to a formula: http://blog.khedan.com/2009/01/eager-loading-from-formula-in.html

NHibernate: How to save a new entity without overwriting the parent:

I'm wondering what the best design would be for persisteing a new child entity with NHibernate without accidentally overwriting the parent in the database.
The problem I have is that the child entity will look something like this:
class Child
{
Parent Parent;
// other fields
}
My problem is that the child has been supplied from the UI layer along with the ID of the parent, and that means that the Parent ref is basically uninitialized: It will have the ID populated but everything else null - because the only way to populate its fields would be an extra round trip to the database to read them.
Now if I call Session.SaveOrUpdate(child) on NHibernate, what's going to happen with the parent. I don't want NHibernate to cascade save the uninitialized parent since that would just destroy the data in the database. How would people approach this problem? Any best practices?
You must use the session.Load(parentid) to get the aggregate root. In contrast to the session.Get() method, this does not actually fetch any data from the database, it just instantiates a Parent proxy object used to add Child objects to the correct Parent in the DB (eg. get the foreign key correctly).
Your code would probably look something like:
// Set the Parent to a nhibernate proxy of the Parent using the ParentId supplied from the UI
childFromUI.Parent = Session.Load<Parent>(childFromUI.Parent.Id);
Session.Save(childFromUI);
This article explains Get/Load and the nhibernate caches really well
You should probably be working with the aggregate root (probably the Parent) when doing Saves (or SaveOrUpdates etc).
Why not just:
Fetch the parent object using the parent id you have in the child from the UI layer
Add the child to the parents 'children' collection
I think you have to overview your mapping configuration for nhibernate. If you have defined on the reference by the child to the parent that hi has to Cascade all, it will update it!
So if you say Cascade.None he will do nothing. All other are bad ideas. Because you allready has the information of this parent. So why read from db agane?!
If your models looks like this
class Parent
{
}
class Child
{
Parent myParent;
}
and you are trying to set the parent and save the child without having a full parent object, just the ID.
You could try this:
session.Lock(child.myParent, LockMode.None);
before saving, this should tell nhibernate that there are no changes to the parent object to persist and it should only look at the object for the Id to persist the association between Parent and Child

Getting multiple queries when transaction is committed, why?

public Parent GetByName(string Name)
{
return _session.CreateCriteria<Parent>()
.Add(Restrictions.Eq("Name", Name))
.SetFetchMode("Children", FetchMode.Eager)
.SetResultTransformer(new DistinctRootEntityResultTransformer())
.UniqueResult<Parent>();
}
public ParentDetailVM GetMeAParent(string Name)
{
Parent parent;
using (var tx = _session.BeginTransaction())
{
//This works well, one single query loading
//both parent and children
parent = _parentRepository.GetByName(Name);
//If I include this as suggested by NHProfiler
//it all of the sudden sends a new query for each child
//and a query for the grandchildren collection
tx.Commit();
}
return Mapper.Map<Parent, ParentDetailVM>(parent);
}
I have checked to make sure that nothing in the mapping files has been set to eager load. I can't figure out why it works if I leave off the transaction commit but otherwise it issues N more queries. Anyone know why this might be happening?
If you examine _session.IsDirty() before committing the transaction my bet is that it will return true. When the transaction is committed the session is flushed and, for some reason, the child objects are loaded to cascade the change.
This is a problem known as "ghosting" or phantom updates. A typical scenario is that a database column is a nullable int but the corresponding object property is non-nullable. When a record with a null value is retrieved, NHibernate sets the property value to 0 and the object is therefore dirty.
The quickest way to troubleshoot this is to turn on dynamic-update for the object using dynamic-update="true" in XML mappings, DynamicUpdate() in fluent, and use a profiler or logging to see which columns are being updated after the select. There's also a utility called Ghostbuster that you can include in unit tests.