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.
Related
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 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.
Is there a way to create an association to an arbitrary domain object in grails?
Something like
class ThingHolder {
DomainObject thing;
}
and then
Book b=new Book(title: "Grails 101").save()
Author a=new Author(name: "Abe").save()
ThingHolder t1=new ThingHolder(thing:b).save()
ThingHolder t2=new ThingHolder(thing: a).save()
So that
ThingHolder.get(t1.id).thing // will be a Book
and
ThingHolder.get(t2.id).thing // will be an Author.
I'm still looking for a grailsier way to do this, but this seems to get the job done.
class ThingHolder {
static constraints = {
thing bindable:true // required so 'thing' is bindable in default map constructor.
}
def grailsApplication;
Object thing;
String thingType;
String thingId;
void setThing(Object thing) { //TODO: change Object to an interface
this.thing=thing;
this.thingType=thing.getClass().name
this.thingId=thing.id; //TODO: Grailsy way to get the id
}
def afterLoad() {
def clazz=grailsApplication.getDomainClass(thingType).clazz
thing=clazz.get(thingId);
}
}
Assuming you have a Book and Author (that do not override the ID attribute for the domain object).
def thing1=new Author(name : "author").save(failOnError:true);
def thing2=new Book(title: "Some book").save(failOnError:true);
new ThingHolder(thing:thing1).save(failOnError:true)
new ThingHolder(thing:thing2).save(failOnError:true)
ThingHolder.list()*.thing.each { println it.thing }
I found some extremely useful tips in these two answers.
How to make binding work in default constructor with transient values.
How to generate a domain object by string representation of class name
UPDATE (based on comment)
Since you don't want to (or can't) extend another class in your domain model, this won't be possible using GORM.
ORIGINAL Answer
Yes, you can do this. It's called inheritance. In your case you would have a Thing which is the super class of both Author and Book.
Your domain model might look like this:
class Thing {
// anything that is common among things should be here
}
class Author extends Thing {
// anything that is specific about an author should be here
}
class Book extends Thing {
// anything that is specific about a book should be here
}
class ThingHolder {
Thing thing
}
Since both Author and Book extend Thing they are considered to be a Thing as well.
However, doing this without understanding inheritance and how Grails/GORM models the data in your database is short sighted. You should research those topics fully to make sure this is really what you want.
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.
I'm facing a issue regarding inheritance in Grails.
I have a domain class Person.grooy:
class Person{
String name
String contactNumber
Address address
}
Now I'm extending Person.groovy for Employee and Customer like:
class Employee extends Person{
String designation
}
class Customer extends Person{
String interest
}
Now I want separate table in my database for Employee and Customer having columns of Person i.e name,contactNumber and associate address key.
How could I achieve this. I searched every where but there is nothing for this aspect.
Is this one approach is not possible in GORM.
Please answer.
Thanks Guys
Finally I managed to get what I want just by placing a grails.persistence.Entity annotation to my child domain classes. I also make my parent i.e. Person.groovy abstract and place in src/groovy.
Now I have database hierarchy as I expected but some scaffold issues in controller still persist that will also sorted out with your help.
You need to disable table-per-hierarchy, which is by default enabled in Grails
class Employee extends Person{
String designation
static mapping = {
tablePerHierarchy false
}
}
table-per-hierarchy Ref
If you put your Person class in src/java or src/groovy it won't be mapped to the db.
Remember to import it into your Employee and Customer classes
import com.yourPackage.Person
class Employee extends Person{
}
It looks like inheritance is not the approach we need to follow here. You should create composition with Person class and it will store the properties of Person class in Employee.
class Employee {
Person person
String designation
static embedded = ['person']
}
Gorm Composition
you can put it inside src/java, but that solution will not be standard, as it really will not be treated as a grails domain example once you get deeper into the application.
For example, if you want to create a controller or a test script on the extended domain as per the previous answer, it will be complicated.
As of grails 2.2.x I believe, grails provides you with mapWith. You can use that for a more maintainable solution
class Employee{
static mapWith = "none"
}