Does Grails / GORM permit relationships in separate java packages? - grails

Grails 3 application -- I've been having trouble with a hasMany property in Grails not populating. I just realized that the owning class is in a different package from the owned class. Am I doing something silly by relating across package boundaries?
Basic example of what I'm doing and observing, in case that doesn't make sense:
Owning Domain Class:
package com.example.project
import com.example.project.configuration.ConfigFile
class MotherClass {
String name
static hasMany = [ configFiles: ConfigFile ]
}
Owned Domain Class:
package com.example.project.configuration
import com.example.project.*
class ConfigFile {
String name
MotherClass motherClass
}
In Bootstrap.groovy:
MotherClass motherClass = new MotherClass(name:"mother").save(failOnError: true)
new ConfigFile(name: "file1", motherClass: mother).save(failOnError: true)
new ConfigFile(name: "file1", motherClass: mother).save(failOnError: true)
assert motherClass.configFiles.size() > 0 #this assertion would fail
In a random service:
assert MotherClass.findByName("mother").configFiles.size() > 0 #this would fail too.
My assertion fails may be caused by some other issue I'm experiencing, but I wanted to verify that crossing package boundaries wasn't to blame.

If you didn't make a mistake in typing above, you are defining a 'motherClass' object but in ConfigFiles setting the motherClass to a 'mother' object.
I assume that's not the case - then, I think you are not providing Grails with enough information about the owner-child relationship.
Typically you would add the children to the owner class and save the owner class and let the saves cascade to children.
MotherClass mother = new MotherClass(name:"mother")
mother.addToConfigFiles(new ConfigFile(name: "file1", motherClass: mother))
mother.addToConfigFiles(new ConfigFile(name: "file1", motherClass: mother))
mother.save(failOnError: true)
And ideally you should have belongsTo clause on the ConfigFile side - otherwise the deletes won't be cascaded. see: http://docs.grails.org/3.1.1/ref/Domain%20Classes/belongsTo.html

The failure of the assertion in BootStrap.groovy makes sense because GORM populates associated, hasMany, sets when an entity is loaded into the Hibernate session. But in this example, GORM won't automatically search the session and add a newly persisted entity into the hasMany sets of its owning entity.
Try the assertion from the other side.
assert ConfigFile.findAllByMotherClass(motherClass)
I know that doesn't solve your problem, but hopefully it points you int the right direction.

Related

Grails GORM Inheritance changing discriminator column

I'd like to use an Enum or String in place of column class to map on table inheritance in Grails.
For exemple
#Entity
#Table(name = "person")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorValue("USR")
#DiscriminatorColumn(length = 3, discriminatorType = DiscriminatorType.STRING, columnDefinition = "CHAR(3) NOT NULL", name = "type")
public class People implements Serializable {
I couldn't find a way to change it into documentation.
Going to try to answer your question but in all honesty unsure where your point is wavering towards since it is left open ended as to to the actual question raised Inheritance and there appears to be no signs of inheritance on example provided.
My first pointer would be here.
This does work or had it working on default grails 3.2.8 but upon updates to latest gorm there was issues with updating existing records. I gave up and did it as separate classes at the time.
If your question relates to having table per class then above setup is what you need for grails.
Typically you would do :
abstract class Something {
static mapping = {
cache true
//tablePerConcreteClass false
tablePerHierarchy false
//discriminator value: 'institution'
}
}
class SomethingElse extends Something {
static mapping={
//discriminator value: 'somethingElse'
}
}
The abstract class definition vs non abstract has different adverse effects into how your tables get created and how your whole model will then work. It all depends on the requirement.
The problem with above is when it comes to querying the class in HQL I faced a problem where when I tried to query instance.class I got a numeric number back from HQL rather than actual domainClass instance and obviously discriminator was first point of reach.
The actual trick in these extended classes is if in HQL something.class does not return actual class name to try
String query = """ select new map(type(s) as className,s.id as id) from Something s """
The type(s) will now return actual string class name. (Maybe where you are stuck)
Usually you can do in HQL:
when s.class = SomethingElse then do something
and HQL will work out the actual className based on that matching domainClass name.
Somehow I don't think this is what you are after though

Grails new Domain object with property map not setting property

EDIT: Per my answer below, this seems fixed by a "grails clean". You bang your head in frustration and you overlook the obvious sometimes.
For some time we've had the following structure of domain objects:
abstract class Company {
String name
...
}
and multiple children similar to the following all with different "owner" objects. Each concrete class has it's own table in the DB.
class CompanyChild extends Company {
static belongsTo = [owner:SomeDomain]
...
}
I'm adding another property to the abstract parent for various reasons, so the parent now looks more like the following (CompanyType is an enum):
abstract class Company {
String name
CompanyType companyType
...
}
This all seems pretty straightforward. Now in company service, somewhere I'm doing this:
log.debug("Saving new company type=$companyType")
def company= new Company(name: 'Acme', companyType: companyType, <other properties here>)
log.debug("company object has type=${company.companyType}")
The log shows...
CompanyService Saving new company type=NONPROFIT
CompanyService company object has type=null
What the heck is happening here? It really seems like ${company.companyType} should not be null.
If I add
company.companyType = companyType
after the object is created it works, but there's something I'm failing to understand.
Edit: grails version is 2.3.11
Sometimes you focus so much on a problem that you don't step back and thing... maybe I need to do a full "grails clean"...
Clean and recompile seems to have been my answer.

Check property is present by property name

I want to check is a string contains the name of a valid property of one of my entity class.
I've figured several keys but at the end i've been unable to make them work and even not sure what it the best practice to do this.
Thanks in advance
Every Grails domain object has an injected domainClass property which exposes a persistentProperties list. You can access the list of properties in this way:
def o = new MyDomain()
o.domainClass.persistentProperties
You can also retrieve this list from the Spring application context, which avoids the need for a domain class instance. Among the Spring beans created for each domain class (four beans for each domain) there is one that has the full name of your domain class with the suffix {{DomainClass}}. Assuming grailsApplication has been injected:
grailsApplication.mainContext.getBean("MyDomainDomainClass").persistentProperties
Within the persistentProperties list, you can search for a property with a given name as follows:
persistentProperties.find { it.name == nameToSearchFor }
Finally i decided to go with
MyClass.metaClass.properties.find { it.name == params.searchedColName }
I think is little better solution than #Andrew von Dollen proposal since i avoid playing with the spring context ... feel that is more groovier this way.

How to define association relationship in grails

UPDATED
I have a domain classes as below
class Training{
// has one createdBy object references User domain and
// has one course object references Course domain
// has One Trainer1 and Trainer2 objects refernces Trainer Object.
}
class Trainer{
String name
//can have many trainings.
//If Trainer gets deleted, the trainings of him must be deleted
}
Class User{
String name
// can have many trainings.
}
class Course{
String name
//If Course gets deleted, Trainings of this course must be deleted
// can have many trainings.
}
I have got a training create page, Where I have to populate already saved Course, User, Trainer1 and Trainer2. I am not saving them while Creating the training.
So, How to specify the relationship in grails
You did not put any effort to searching answer for yourslef. There are plenty basic examples and blog posts how to map relations in Grails. You should start with Grails documentation of GORM - Grails' object relational mapping. You can find it here.
I see some minor flaws in yout initial design: ie why should training be deleted if user is deleted when trainings will obviously tie with many users. Can training exists without trainers or vice versa ?
I would start with something like this:
Class Training {
static hasMany = [users: User, trainers: Trainer]
static belongsTo = Course
}
Class Trainer {
String name
}
Class User {
String name
}
Class Course {
String name
static hasMany = [trainings: Training]
}
EDIT: I have to agree with Tomasz, you have jumped here too early without searching for answers yourself. Grails.org has good documentation about GORM with examples too.

Grails: Rollback associations done by data binding in a service

Given the following two domain classes:
class Book {
String title
static hasMany = [authors: Author]
static belongsTo = Author
static constraints = {
title(nullable: false)
}
}
class Author {
static hasMany = [books: Books]
}
We create and persist domain objects in services and make use of the data binding feature of Grails. Such a method looks like the following one:
def createAndPersistBook(params) throws ValidationException {
log.debug("Attempt to create and persist book")
Book book = new Book(params)
book.save(flush: true, failOnError: true)
log.debug("Created: ${book}")
book
}
When we pass the params map
params = ["authors": "[2]"]
to the service method (there is no title defined thus validation will fail) the association from the newly created book to the already existing author (and vice-versa) is done by data binding. But since the title is nullable: false and not defined a ValidationException is thrown and the transaction is rolled back.
What we expected now is that the book is not being saved, but Book.list().isEmpty() returns false. We think that this is because of the dirty-check by hibernate, meaning the books collection of the existing author has changed and will be persisted and this save gets cascaded to the book instance.
What is the best way to prevent grails from saving the book in this scenario? Or why is the association done by data binding not properly rolled back when validation fails?
If you've specified that your service is transactional, any uncaught exception will cause a transaction to rollback within a service method. The only thing that might stand in your way is if your RDBMS does not support true transactions/rollback.
Have you specified whether the service is transactional? You should have a statement such as below to declare the service is transactional.
def transactional = true

Resources