Issue Details (XML | Word | Printable)

Key: GRAILS-3320
Type: Improvement Improvement
Status: Open Open
Priority: Major Major
Assignee: Graeme Rocher
Reporter: Horst Krause
Votes: 1
Watchers: 2
Operations

If you were logged in you would be able to see more operations.
Grails

(GORM) replacement for hibernate not-found="ignore"

Created: 11/Aug/08 03:00 PM   Updated: 03/Oct/08 05:26 AM
Component/s: Persistence
Affects Version/s: 1.0.3
Fix Version/s: None

Time Tracking:
Not Specified

Environment: WinXP


 Description  « Hide
I work since Grails 0.5 with Hibernate Mappings. Now I'm migrating to 1.0.3 and try to use just the mapping-Features in den domain classes.
It works quite good except one thing:
I have an object "project" and the projects should have subproject and each project has a parent. So there is a project tree to navigate through. And there is also one root-project in the tree which does not have a parent. In the database this project has a parent value of -1. A database object with -1 certainly does not exist. In hibernate mapping (see below) I used not-found="ignore" to avoid any error messages for a not existing project object -1.

I'm searching for a possiblity to solve this just with domain class "static mapping" and without any hibernate mapping?

Graeme Rocher said on grails-user list: notfound="ignore" is the default mapping for GORM, so its enabled already

But Peter Ledbrook said the following and asked me to raise an issue: It seems that "ignore" is the default for many-to-one and many-to-many, and that is only if the collections are fetched lazily. one-to-many and eagerly fetched collections have the default setting of "exception". I think the only workarounds are to patch Grails or use the Hibernate mapping file.

BTW: I really don't know, if my parent-project <-> sub-project relation is many-to-one or a one-to-many (or both) - but in the end it does not work.



 All   Comments   Work Log   Change History      Sort Order: Ascending order - Click to sort in descending order
Horst Krause added a comment - 11/Aug/08 03:05 PM
The domainclass is:
class Project implements Comparable
{
String name;
Person intPerson;
Person extPerson;
String isCompany;
Date begindate;
Date enddate;

static hasMany = [currentUsers:Person, subprojects:Project]
static belongsTo = [parentProject:Project]
static mappedBy = [currentUsers:"lastProject"]

static constraints = {
name(blank:false, nullable:false, size:1..100)
parentProject(nullable:true, validator: {return (true)}) //nullable:false,
isCompany(blank:false, inList:["Y","N"])
begindate(attributes:[precision:"day", years:"${2008..2015}"])
enddate(attributes:[precision:"day", years:"${2008..2015}"]
)
fullName(editable:false)
}

static mapping = { version false currentUsers column:'FK_PROJECT_ID' intPerson column:'FK_INT_PERSON_ID', lazy:true extPerson column:'FK_EXT_PERSON_ID', lazy:true parentProject column: 'FK_PARENT_PROJECT_ID', lazy:true subProjects column: 'FK_PARENT_PROJECT_ID', lazy:true }

static fetchMode = [parentProject:"lazy",subProjects:"lazy"]

static transients = ['fullName']

public int compareTo(Object o) { return getFullName().toLowerCase().compareTo(o.getFullName().toLowerCase()) }

String toString() {
return getFullName() + " (ID:${id})"
}

String getFullName() {
def s =""
if (isCompany.equals("N") && (id != 0)) {
if ((parentProject)
&& (parentProject.id >= 0)) { s = parentProject.getFullName() + "/" }
}
s += name
}
}

The exception is:

org.hibernate.ObjectNotFoundException: No row with the given identifier exists: Project#-1

at Project$$EnhancerByCGLIB$$71ab07ff.getMetaClass(<generated>)

at C_grails_1_0_3_tk_dev_zesadmin_grails_app_views_project_list_gsp$_run_closure15.doCall(C_grails_1_0_3_tk_dev_zesadmin_grails_app_views_project_list_gsp:101)

at C_grails_1_0_3_tk_dev_zesadmin_grails_app_views_project_list_gsp.run(C_grails_1_0_3_tk_dev_zesadmin_grails_app_views_project_list_gsp:89)


Derek Alexander added a comment - 03/Oct/08 03:52 AM
Think I've just encountered a similar problem.

In my case the legacy database contains orphaned foreign keys.

e.g.

class Report { Person author Person subject }

Where the Report table contains person keys for rows in the Person table that don't exist.

Fetching Reports and eagerly fetching their Person typed fields, I get an exception:

Caused by: org.hibernate.ObjectNotFoundException: No row with the given identifier exists: ...

Would like an easy way to just ignore these cases (so the unmatched Person typed fields would just contain null)

e.g.

static ignoreNotFound = ["author", "subject"]


Derek Alexander added a comment - 03/Oct/08 05:00 AM
Checking over my code, it turns out that it was a lazy fetch of the Person typed fields.

Derek Alexander added a comment - 03/Oct/08 05:26 AM
Aplogies for posting this piecemeal. While I thought I was using lazy loading for this field (as I'd never specified for it to be eagerly fetched) it turns out that lazy loading wasn't possible as it is a one-to-many (so same as one-to-one from its point of view) nullable field.
The fact it is nullable prevents hibernate from putting a proxy there and it thus might as well try and populate it.

This conceptual limitation for Hibernate is explained properly here: http://www.hibernate.org/162.html#A3

However, all this just means I still need to be able to specify something like: static ignoreNotFound = ["author", "subject"]

As a workaround will have to see if the db can be cleaning up dba's persuaded to add constraints.
If that isn't possible I'll have to revert to Hibernate mappings instead of GORM.
My understanding is that it isn't possible to mix and match hbm.xml, hibernate annotations or GORM (i.e. one must choose
one approach for all domain classes) so this would be a real pain.