Grails custom class mapping for table-per-hierarchy domain - grails

Grails creates a class column in the database for a table-per-hierarchy mapping and uses full class name for its typed queries. So a saved instance of a domain class class Volvo extends Car in package com.example will generate a com.example.Volvo entry in the class column of the Car table. This obviously limits package refactoring or reusing pre-existing value sets from legacy databases.
Is it possible to use custom class mapping for a table-per-hierarchy domain class strategy? For example, to map com.example.Volvo domain class to always generate a VOLVO value in the Car's class table?

Related

Which is the parent class for grails domains

Which class/interface is the parent for all the grails domains.
I just want to know which class actually executes save method of a grails domain
Let us suppose we have grails domain with name book
Book book = new Book("1")
book.save()
There is no save method in book class so where does it actually resides.
https://gorm.grails.org/6.0.x/api/org/grails/datastore/gorm/GormEntity.html
GormEntity is the parent for all domains classes.

Gorm mapping for inheritance

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"
}

Grails Domain Class Inheritance: Configure Class Column

I use inheritance in Domain Classes in my Grails app. Obviously, inheritance adds a "class" column to my database. The content of the "class" column is the fully qualified name of the Domain Class, e.g. com.myapp.MyClass.
Now if I ever so some refactoring and the class name is no longer com.myapp.MyClass but e.g. com.myapp.mypackage.MyClass, then the database still contains the old class name which now no longer exists in the app.
Is there any way to configure the string that is put in the "class" column? Like another unique identifier for the class which is then mapped to the class name in my Grails config or something like this?
I think what you need is discriminator for the class.
By default when mapping inheritance Grails uses a single-table model
where all classes share the same table. A discriminator column is used
to determine the type for each row, by default the full class name. ref
You can map it like this:
class PodCast extends Content {
…
static mapping = {
discriminator "audio"
}
}
Look this documentation it gives you more options to customize it in more details
http://grails.org/doc/latest/ref/Database%20Mapping/discriminator.html

How to design domain classes in Grails?

Given these functional requirements:
User Management
Administrator
Librarian
Borrower
*The users have the option of logging-in via OpenID.
Property Management
Book
Memorandum
Circular
License
Normally, I would implement these in Java as:
interface User {}
class Librarian implements User {}
class Administrator implements User {}
class Borrower implements User {}
class OpenID {} //all Users HAS AN OpenID attribute (NULL if non-openId login)
interface Property{}
class Book implements Property{}
class Memorandum implements Property{}
class Circular implements Property{}
class License implements Property{}
But our project will use Groovy & Grails, which I haven't experience using yet. My question is,
how should the domain classes be designed based on the requirements above? I can't use an interface, and it seems inheritance is not a good practice. My idea is to use composition, though I'm quite bothered by the database tables that would be generated. What are the best practices in this situation?
Well first of all lets correct it, you can use inheritance in this case. You just need to change the convention of has a relationship to is a relationship.
Few factors to keep note of:
1. Grails works on convention over configuration.
2. You can use GORM which wraps the persistence layer and creates an Object Mapping for the underlying persistence layer with the help of Hibernate.
As per your functional requirement:-
If you do not want to have the User as part of persistence you can have an abstract class User which can hold the common properties of the User including the openId attribute. It has to be placed in src\groovy directory as per convention (since the base class is abstract, dependency injection will be defied)
The same goes for Property. Abstract Property class in src\groovy.
Now coming to the business models, extend each of the concrete entities (domain classes) from the abstract parent.
Summary:-
Create grails app
Under src\groovy(for example, I am considering a basic structure):
User.groovy:-
abstract class User{
String name
String emailId
OpenID openId
}
Property.groovy:-
abstract class Property{
String propertyName
}
Under grails-app/domain:
Librariran.groovy:-
class Librarian extends User{
//Attributes specific to Librariran
static constraints = {
}
static mapping = {
}
}
Book.groovy:-
class Book extends Property{
//Attributes specific to Book
static constraints = {
}
static mapping = {
}
}
So on and so forth. Groovy objects under grails-app/domain are considered concrete entities by Grails convention. More information you can obviously find here. You can also use composition if you come across scenarios, in fact I already mentioned that in User having OpenId.
Note:- This is context to latest version of Grails (> 2.x)

Mapping legacy domain class using Grails

I am trying to map a legacy domain class to my grails class, but when table is generated, the field associated with legacy class is Tinyblob, and not a BigInt linked with ID, and foreing key stuff.
class NewClass implements Serializable {
GrailsEntityA grailsEntityA
GrailsEntityB grailsEntityB
LegacyEntity legacyEntity
}
The table has foreing keys for GrailsEntityA and GrailsEntityA but not for LegacyEntity, the type is tinyblob, without relationship with the LegacyEntity table.
Is it possible do this? How?

Resources