Grails Domain Class Inheritance: Configure Class Column - grails

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

Related

GORM creating tables with base class name instead concrete class name

I Have the following domains in my gorm package:
Domain.groovy
package gorm
class Domain {
String createdBy
static constraints = {
}
static mapping = {
tablePerHierarchy true
}
}
User.groovy
package gorm
class User extends Domain {
String name
static constraints = {
}
}
I want a table named user with the fields of the base class domain, but instead GROM generate a table whit this specification
create table domain
(
id bigint auto_increment
primary key,
version bigint not null,
created_by varchar(255) not null,
class varchar(255) not null,
name varchar(255) null
)
I'm using mysql driver with grails 2.5.6.
It generates the table with the name as domain because you are using tablePerHierarchy true in your mapping.
Basically, you will get one table where you can set different discriminators for the subclasses.
See here for more information on inheritance strategies: http://docs.grails.org/2.5.x/guide/single.html#GORM
(scroll down to: 7.2.3 Inheritance in GORM)
If you simply want schema-export to generate your table with the name as user, then you would need to add the following to your mapping block in the Domain class:
table 'user'
so the entire mapping block would look like:
static mapping = {
table 'user'
tablePerHierarchy true
}
However, this may not make sense to name the table user if you have other classes extend from Domain.
(and if you don't plan to have other classes extend from Domain, then just add your fields into your User domain).
If you want to generate two tables (Domain and User), then set tablePerHierachy false.
Here is a great write-up with examples that may help you decide which way you want to go for your project:
https://sysgears.com/articles/advanced-gorm-features-inheritance-embedded-data-maps-and-lists-storing/
As a side note: I'm not keen on the name Domain for a domain class; it is too generic and may get confusing when you are talking about the specific Domain class vs domain classes. At least name it BaseDomain.

Grails custom class mapping for table-per-hierarchy domain

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?

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

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?

can we have multiple aliases for a Domain Class Attribute in grails

I have many domain classes in my application an for Audit logging I need the name attribute of each Domain class. unfortunately the name attribute is not generic in all Domains.
In my Audt log class I get the type of object modified/created/deleted and then save the id right now (which is common code since all domains have 'id' attribute) but now if I want to get the name attribute out of the domain from the ID, each domain has a different name attribute, like Resource Domain has resourceName, User domain has userName and so on... soI will have to handle each domain seperately (like have a map or bunch of switch statements for getting the name attribute from the Domain class name).
Is there a way I can have an alias mapping for each domain class's name field to be called 'name' . there should not be any change to the actual attributes in the Domains in whatever changes I do, I can add a column to Audit Domain but not other table changes.
Thanks in Advance
I don't think that there's any way to do this automatically.
As you guessed, you're going to either have to change all of the domain objects so that they have a 'name' attribute, or somehow maintain a map of which attribute in each class is to be considered the 'name'.
I suppose that one answer might be to add a getName() method to each of the domain classes, and return the appropriate value from that method.
If you really don't want to modify the domain objects at all, you can use groovy meta-object programming (MOP) to inject this method into each domain class from the BootStrap class.

Resources