I have a domain object that has a property that i want to be used as the id by GORM, the reason being is that ill be saving lists of this object and i want existing rows to be updated if the id already exists in the database
Lets assume that my property i want as the PK is called listId
Ive seen several approaches to this, which is best?
1:
id generator: 'identity', column: 'listId'
2:
static mapping = {
id generator:'assigned'
}
def getKey = {
return listId;
}
or something entirely different?
static mapping = {
id generator: 'assigned', name: "listId", type: 'string'
}
Related
Suppose I have the following:
class ObjectA implements Serializable {
Foo foo
String objectType
static mapping = {
version false
id composite: ['foo', 'objectType']
foo column: 'foo'
objectType column: 'objecttype'
}
}
Now, I need to reference this object from another Domain.
class ObjectB {
ObjectA objectA
columns {
objectA{
column name: 'foo'
column name: 'objecttype'
}
}
}
When I try and load an ObjectB, I get the following:
Cannot treat multi-column property as a single-column property
How should I be mapping this?
What are you attempting to do with the columns section, I only ask because I have am unfamiliar with that concept? This stack overflow link may help.
But, as show in link, if you want to reference the object you should create a relationship (the one in the example is unidirectional) between the two domains.
class Object B {
static hasOne[objectA:ObjectA]
....
}
There really isn't much more to it then that. You can access the fields from objectA within you views just by using ObjectBInstance.objectA.channelName.
I have an entity, Student, defined in Student.groovy as:
#EqualsAndHashCode(includes = ['id'])
class Student {
Long id
String name
String type
University university
static mapping = {
university column : 'UNIVERSITY_ID'
}
}
and a University entity, defined in University.groovy as:
class University {
Long id
String name
static mapping = {
id column : 'id', generator : 'assigned'
}
}
I've been trying to switch from calling
Student.list(sort: ..., order: ...)
to calling:
Student.findAll("from Student s where type = :type ", [type : 'T'], [ sort : 'name' ])
This fails to order correctly by the name field. The previous version, using list worked fine.
I've also tried calling something like
Student.findAll(sort : 'name') { type == "T" }
which worked fine like this, but when trying to sort by the university.name
Student.findAll(sort : 'university.name') { type == 'T" }
it raised an error regarding the university.name field not being found.
Anybody have any idea on how to do this properly?
Thank you.
Use executeQuery instead of findAll - they should function the same, but I've found that executeQuery is for some reason a more direct caller of the HQL, and findAll fails or returns unexpected results in some cases.
So that first query would be
Student.executeQuery(
'select s from Student s where s.type = :type order by s.name',
[type : 'T'])
and ordering by university name would be
Student.executeQuery(
'select s from Student s where s.type = :type order by s.university.name',
[type : 'T'])
I like HQL and tend to use it a lot, but it couples you to Hibernate and relational databases - if you want to switch to a NoSQL database these queries will fail. Criteria queries, "where" queries and finders all use criteria queries internally, and those are converted to native query API calls by the GORM implementation.
The equivalent criteria queries would be
Student.withCriteria {
eq 'type', 'T'
order 'name', 'asc'
}
and
Student.withCriteria {
eq 'type', 'T'
university {
order 'name', 'desc'
}
}
Some unrelated notes:
You shouldn't use id in equals or hashCode calculations; if you have a persistent Student and a new non-persistent instance with the same name, type, and University, they should be considered equal, but since the non-persistent instance's id will be null they'll be considered different.
You don't need to specify the id property - Grails adds it and the version field to the bytecode via an AST transformation during compilation.
There's no need to map the column name of the university property to 'UNIVERSITY_ID' - that's what it would be anyway.
You can omit the redundant column setting in the id mapping.
Here's the Student class with cruft removed:
#EqualsAndHashCode(includes = ['name', 'type', 'university'])
class Student {
String name
String type
University university
}
and University:
class University {
String name
static mapping = {
id generator: 'assigned'
}
}
I've read through a lot of posts and docs and must be missing something.
In my application (model below) I am having a data issue that seems to be out of my control where I have a categoryId in the join table JOBORDERCATEGORIES that has no corresponding row in the CATEGORY table. I am accessing the category data through getJobCategories() in the JobOrder. This is producing the following error when my Category table is missing a referenced row:
2012-03-07 08:02:10,223 [quartzScheduler_Worker-1] ERROR listeners.SessionBinderJobListener - Cannot flush Hibernate Sesssion, error will be ignored
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.matrixres.domain.Category#416191]
and my code is halting.
I have tried using ignoreNotFound but it is not helping me to get past the error above.
If I missed a post on the solution to this problem please link me to it otherwise thoughts are welcome on how to move forward. Perhaps there is a more direct route I will have to hammer in to achieve my goal of getting a good category list, but I am not familiar enough with the framework to know what is next. As a note, I cannot write to any of these tables.
thanks, rich
A simplified Version of my Model:
Job Order Object:
class JobOrder {
def getJobCategories() {
def cats = []
try {
def jocategories = this.categories
if(!jocategories.isEmpty() && jocategories!=null){
println "we got categories for ${this.id}"
jocategories.each { cat ->
if(cat?.parentCategoryID == 0){
if(cat.occupation != null){
cats << cat.occupation
} else {
cats << cat.name
}
}
}
}
} catch(e) {
cats << "Other Area(s)"
}
cats
}
static mapping = {
table 'dbo.JOBORDER'
version false
id generator: 'identity', column: 'JOBORDERID'
/*
* several other mapped columns deleted here
*/
categories joinTable:[name:'jobOrderCategories', column: 'categoryId', key:'jobOrderID']
}
/*
* several properties deleted here
*/
static hasMany = [categories: Category] //several other hasMany associations exist
}
Category Object:
class Category {
static mapping = {
table 'CATEGORY'
version false
id generator: 'identity', column: 'categoryID'
occupation column: 'OCCUPATION'
name column: 'NAME'
parentCategoryID column: 'PARENTCATEGORYID'
/*
* several other mapped columns deleted here
*/
jobOrders joinTable:[name:'jobOrderCategories', column: 'jobOrderID', key:'categoryId']
}
String name
String occupation
int parentCategoryID
/*
* several properties deleted here
*/
static belongsTo = [JobOrder]
static hasMany = [jobOrders:JobOrder]
}
Join Table:
class JobOrderCategories {
static mapping = {
table 'JOBORDERCATEGORIES'
version false
isDeleted column: 'ISDELETED'
jobOrderID column: 'JOBORDERID'
categoryId column: 'CATEGORYID'
}
Boolean isDeleted
Integer jobOrderID
Integer categoryId
}
These kinds of situations aren't the most fun, but I have had to deal with this kind of Roll-Your-Own ORM problems before ;) Basically what you're going to want to do here is store the object properties not typed as Object references, but as ints, and while you'll lose some of the dynamic finder things GORM makes so nifty, you'll have a fairly straight-forward means of accessing the data that doesn't involve tangling yourself up with Hibernate's innards.
Basically, this will involve ditching your hasMany and belongsTo properties on JobOrder and Category. Instead, you'll want to do things like
def myJobOrder = JobOrder.get(yourId);
def myCategoryIds = JobOrderCategories.findAllByJobOrderID(myJobOrder.id)
def myCategories = Categories.withCriteria {
in('id', myCategoryIds)
}
You can put variations of those traversals in helper methods on your classes, like for example, your getJobCategories method could become
class JobOrder {
//...
def getJobCategories() {
def myCategoryIds = JobOrderCategories.findAllByJobOrderID(this.id)
def myCategories = Categories.withCriteria {
in('id', myCategoryIds)
}
}
}
And so on. This is definitely not the prettiest thing in the world to deal with, and you lose your ability to traverse through things easily with GORM (ex a
jobOrder.withCriteria {
categories {
eq('name', blah)
}
}
becomes a executeQuery type of situation.)
But overall, its not too bad to deal with :)
Hope that helps!
I'm new to Grails&GORM so this may be a quick question. We are currently looking at using GORMs mongo support and I am having a few issues mapping to existing collection data. I basically want to map to a hierachical object structure whereby my object "Merchant" has reference to another parent merchant. The BSON structure is fairly simple i.e.:
{
name: "name",
parent_id: ObjectId("[Object Id ref]")
}
In my model I attempted to map this relationship as follows:
class Merchant {
ObjectId id
String name
Merchant parent
static belongsTo = [parent: Merchant]
static mappedBy = [parent: "parentId"]
static mapping = {
collection "merchants"
}
static constraints = {
}
}
This resulted in the following BSON:
{
"_id" : ObjectId("4ea6be91ce5f56cd49f43ab8"),
"name" : "where will you g",
"version" : NumberLong(1),
"parent" : {
"$ref" : "merchants",
"$id" : ObjectId("4ea6be91ce5f56cd49f43ab8")
}
}
This has two issues, namely:
- The name of the parent merchant field is "parent" and not "parent_id", which is required.
- The value of the parent field has additional meta infomation other than the id in i.e. $ref : "merchants".
Is there anyway I can keep our existing BSON structure and still have a rich object mapping.
Cheers, Chris.
For the two issues, you need an additional mapping:
static mapping = {
collection 'merchants'
parent attr:'parent_id', reference:false
}
You should also drop the mappedBy block, since you only need it when there are multiple fields of the same type.
Finally, note that reference:false is the default in recent versions of the plugin (1.2+ I think). Note that 'attr' is named 'columnName' in other flavours of GORM.
Working with Grails 1.3.7, I've to deal with a legacy DB. I've a domain object ''Cake'' which have it's own collection of embedded ''Ingredients'', in a join table.
Ingredient.groovy
class Ingredient {
String name
IngredientCategory category
mapping {
table "foo_ingredient"
version false
id composite:['name', 'category']
columns {
word column:"the_name"
category column:"lol_category_id"
}
}
}
Cake.groovy
class Cake {
String name
static hasMany = [ ingredients : Ingredient ]
static mapping = {
table "foo_cake"
version false
columns {
id column:"id"
name column:"the_name"
}
ingredients joinTable: [
name : "foo_cake_ingredient",
key : "cake_id"
]
}
}
Problem is, Grails expect that the table ''foo_cake_ingredient'' to have two columns ''ingredient_name'' and ''ingredient_category_id''. I would like to specify manually those column names and not let Grails (wrongly) guess those. I can't figure how to do that.
I showed how to do this here: http://grails.1312388.n4.nabble.com/Composite-foreign-key-td3046351.html#a3046436
You probably have to create a hibernate xml mapping for the two tables in this relationship.
Have you read http://jasonrudolph.com/blog/2006/06/20/hoisting-grails-to-your-legacy-db/ ?