domains have some common fields,extends domain or embedded? - grails

when i design database.I use embedded to embed common fields.but it's can't init dateCreated and createdBy,what'd i do?extends domain or embedded is right way to handle common fields?
code to say?
class Created {
Date dateCreated
Long createdBy
def beforeInsert()
{
dateCreated= new Date()
createdBy=0
}
}
class Updated {
Date lastUpdated
Long updatedBy
//it works?
def beforeUpdate(){
lastUpdated=new Date()
updatedBy=0
}
//it works?
def beforeInsert(){
lastUpdated=new Date()
updatedBy=0
}
}
class CreatedUpdated {
Created created
Updated updated
//Must use the embedded option, or the type of exception, can not find CreatedUpdated
static embedded = ['created','updated']
}
class Term {
String name
CreatedUpdated createdUpdated
static embedded = ['createdUpdated']
Term parent
static hasMany =[terms:Term]
static mapping = {
version false
}
String toString()
{
name
}
static constraints = {
name unique:true,size: 1..20
parent nullable: true
createdUpdated display:false,nullable:true
terms display:false
url url: true
}
}
or use extends?
class Term extends CreatedUpdated{
String name
Term parent
static hasMany =[terms:Term]
static mapping = {
version false
}
String toString()
{
name
}
static constraints = {
name unique:true,size: 1..20
parent nullable: true
terms display:false
url url: true
}
}
`
what is right to me?

I'd definitely make this example embedded rather than inherited. I don't think you should make this call based solely on the fact that objects contain common fields. Instead, you should use inheritance if it makes sense for your model using standard OO design techniques. For example, if "myClass is a myBaseClass" doesn't hold true, inheritance is probably the wrong solution.
In general, I'd stay away from classes like CreatedUpdated that are just a collection of properties and not an actual object from your domain. Java/Groovy has only single inheritance, so this only works if you have one base class like this.
Also, for that particular case, created and updated timestamps can automatically be applied by GORM. If you're using spring security, check out the audit-trail plugin for automatically creating createdBy and updatedBy columns.

In this particular case audit-trail plugin should suffice the requirements. However if you have such requirement for other fields wherein no plugin is available, then one of the possible solution could be to inject such common fields at compile time via AST Transformation. Internally audit-trail plugin uses this concept to inject those fields. Depending upon your requirement you can either use Global AST Transformations or Local AST Transformations.

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 Scaffolding

I am recently working on grails and would like to know how to do more complex scaffolding
For example, if I want to Scaffold a class
class Book{
Author a
Publisher p
// ....
}
Author class
class Author{
String firstName
String lastName
// ...
}
Publisher class
class Publisher{
String name
String address
// ....
}
Now if I have a BookController
class BookController{
static scaffold = true;
}
I have a layout of
Author Publisher
However if I want a layout with
AuthorID AuthorFirstName AuthorLastName PublisherName PublisherAddress
I have looked through the http://grails.org/doc/latest/guide/scaffolding.html, however, I am unable to set it to the given property. I would like to know I am able to accomplish it? A tutorial would be helpful.
The scaffolding plugin within Grails is not designed to handle these types of complex views out of the box. You have a few options:
Use the install-templates command and modify the scaffolding templates to handle your needs.
Re-design your domain class to use embedded Author and Publisher. This will change the scaffolding output, but it also will change a lot more too. I wouldn't use this option unless you understand all the changes this will make to your domain model.
Generate the code using scaffolding then customize the output to suit your needs.
Of the three options presented here I would recommend the third as it makes the most sense to address the narrow scope of your issue.
You could also use transients. But transients aren't displayed by default.
You need to modify the templates and explicitly hide otherwise hidden fields using constraints i.e. id
NOTE: code below untested, for illustration purposes only.
//optional, but allows code completion in IDE ;-P
String authorName
String getAuthorName(){
return a.firstName + ' ' + a.lastName
}
static transients = [authorName:String]
static constraints = {
id(display:false)
}

grails: scaffolding create view for domain with hasMany relation

Let's assume the following (simplified) domain classes:
class Person {
static hasMany = [stringProperties: StringProperty]
static constraints = {
}
}
and
class StringProperty {
String name
String value
static constraints = {
name blank:false
value blank: true
}
}
When scaffolding generates the create view, there is no option in the gsp to create a StringProperty from Person.
Does a plugin exist or does somebody know a best practice, that can render a sort of create ui that allows to create members of a hasmany relation.
I'm just asking before i take the time to modify the scaffolding templates.
This is one of the areas where a plugin or enhanced scaffolding would be welcomed by the community. If I had the time I would take the information presented here and make a plugin for it. I have used this approach a few times and it works well.

Update "lastUpdated" Field in Parent Domain Class in Grails

I have a parent domain class the has a hasMany of another domain class. Both the parent and the child domain classes have the lastUpdated and the dateCreated fields. My issue is that when I update a child domain class, I need the parent domain class to reflect that change and update its lastUpdated field as well.
Is there any mapping or other configuration between the parent and child that Grails provides that would implement this feature?
Update
I added the following lines to the child domain class:
def beforeUpdate = {
parent.lastUpdated = new Date()
}
I also had to make sure in the controller that when I updated a child, I also had to save the parent as well to persist the new lastUpdated field. This seems to work fine, but I would still like to know if there is a mapping or something similar that would do this.
I have a feeling your suggested implementation will be buggy. You're updating the parent by setting the lastUpdated date manually, which might cause grails to update lastUpdated again after it does dirty checking on it. If that's the case, you would actually end up with a lastUpdated time that occurred after the date you original set. In your testing, this might be only a few (milli)seconds, but you can't guarantee that.
Not only that, but your implementation is harder to maintain since you have increased the coupling of Parent and Child.
Might I suggest another implementation? The lastUpdated field is supposed to represent the time the specific domain object was updated. The date you're looking for is not quite the same thing, so I wouldn't try to use the existing convention in the "wrong" way. It sounds like the date you want for the parent object is "the last time a child was modified".
Use a formula instead.
To do that, you could use a formula. With a formula, you get exactly what you want without having to directly modify the parent object, and you can still use dynamic finders and other Grails sugar.
class Parent {
...
Date lastChildUpdated
static hasMany = [ children: Child ]
static mapping = {
...
lastChildUpdated formula: '(SELECT max(c.last_updated) FROM child c WHERE c.parent_id = id)'
}
}
GORM will load the value of the formula in whenever you read the object from the database. Now, whenever you save a Child, the parent will have an accurate value for that property without having to touch the Parent.
I used a hack. I have added a Long updateTrigger field to my parent domain class and a touch method:
class Parent {
Long updateTrigger
static mapping = {
autoTimestamp true
}
static constraints = {
updateTrigger(nullable:true)
}
public touch() {
if (updateTrigger == null) updateTrigger = 0
updateTrigger++
this
}
In the update/save actions of the child controller, I just call:
child_instance.save() // save the child
child_instance.parent.touch().save() // updates parent's time stamp
This will increment the updateTrigger value, and the save() will automatically update the lastUpdated field thanks to the autoTimestamp set to true in the mapping. updatedTrigger is set to be nullable so that it doesn't invalidate any existing database table and therefore can be added anytime to any domain class.
In one of my project where the domain was like.
A Program has many AdvertisingMaterial and we have subclasses of AdvertisingMaterial, FlashAd, ImageAd etc. The user want the ability to filter the programs which has flashAds, imageAds etc. Now I need to do the filtering on the basis of the class property that we have in database table (When table tablePerHierarchy is true). So I did some changes in my domain class to get this property.
class AdvertisingMaterial {
String className
static constraints = {
className(nullable: true)
}
static mapping = {
className formula: 'CLASS'
}
}
Now what I can use this className field in my dynamic finders and criteria query as well. So I can do something like
List<AdvertisingMaterial>adMaterials=AdvertisingMaterial.findAllByClassName("com.project.FlashAd")
static mapping = {
fullName formula: "CONCAT(FIRST_NAME,' ',LAST_NAME)"
totalAmount formula: "SUM(AMOUNT)"
}

How do define default display order with derived domain classes in Grails?

In Grails 1.2.1, I use a base domain class and derived domain classes and define constraints in all of them. The scaffolding templates (I use the i18n ones) determine the default field display order based on these constraints. My problem: No matter what I do, the fields from the base class are always displayed before the fields from the derived classes.
So here's an example of such classes:
abstract class BaseEntity {
String name
String description
String link
static constraints = {
name(blank: false)
description(blank: true, maxSize: 131072)
link(url: true, blank: true)
}
}
class BacklogItem extends BaseEntity {
String type
String priority
static constraints = {
name(unique: true)
type(inList:["Bug", "Enhancement", "New Feature", "Task"])
priority(inList:["Low", "Medium", "High"])
description()
link()
}
}
Now I'd like the fields to show up in the order as defined in the Item constraints (description and link at the end). But no matter what I do, name, description and link are always the first three fields in create/show/edit, due to the base class, even when I try to force them to the end in the derived class constraints.
How would you solve this?
I will move the constraints away from the base class and duplicate them in each derived class. This means code duplication, but it allows me to specify the display order in each (derived) class the built-in Grails way.

Resources