Prefix column names in GORM - grails

with every project, I automatically run into a problem with reserved SQL word when I use properties like status or user in my Grails domain classes.
So I always have to add a
static mapping = {
status column:'prefix_status'
}
to my classes.
I now wonder if there is an easy way to prefix all columns with a given string?
If there is nothing out of the box, I guess it would be possible to create a plugin which automagically injects such a mapping in all domain classes - can someone point me to a code example which modifies a class whenever it changes?

This is already answered in the manual:
Object Relational Mapping (GORM) - Custom Naming Strategy
Add to DataSource.groovy Config:
hibernate {
...
naming_strategy = com.myco.myproj.CustomNamingStrategy
}
Custom Naming Class (under src/groovy/com/myco/myproj/CustomNamingStrategy.groovy):
package com.myco.myproj
import org.hibernate.cfg.ImprovedNamingStrategy
import org.hibernate.util.StringHelper
class CustomNamingStrategy extends ImprovedNamingStrategy {
String propertyToColumnName(String propertyName) {
"prefix_" + StringHelper.unqualify(propertyName)
}
}

Related

Grails query on a domain with a property that is a set of strings

I am trying to query a domain that looks like this:
class MyDomain {
String something
String somethingElse
Set someStrings
static hasMany = [someStrings: String]
static mapping = {
//... etc.
someStrings: cascade: 'all'
//... etc.
}
}
The domain is in a dependency I didn't write and can't modify.
I would like to find all MyDomains where the Set someStrings contains, say, 'xyz'.
Please show me how, dynamically, with a criteria, or whatever you consider the best practice, I can do this in Grails. My project and the dependency are using Grails 2.44.
In my opinion, using a Collection as a property in a grails Domain is already an anti-pattern, so asking for a "best practice" on top of that is kind of ironic.
FWIW, here's my attempt.
Grails builds a table for your Set of strings, so you can use a classic SQL query, and bind the results to the domain class, like this:
import myapp.MyDomain
class MyDomainService {
List<MyDomain> findByKeyword(String keyword) {
MyDomain.withSession {session ->
def query = session.createSQLQuery("select distinct main.* from MY_DOMAIN as main inner join MY_DOMAIN_SOME_STRINGS as detail on main.id=detail.MY_DOMAIN_ID where detail.SOME_STRINGS_STRING = :keyword")
query.addEntity(MyDomain.class)
query.setString("keyword", keyword)
query.list()
}
}
}
I could not test the code, so there may be typos. I believe that my table and column names match what grails would generate for your example. In any case the principle of binding a domain class to a resultset works in my code.
UPDATE:
Not sure if it will work, but you could try this:
MyDomain.findAll {
someStrings.contains "xyz"
}
It is theoretically possible within the DSL of where queries, but I haven't tried it. I'd be impressed if they thought about this.

Grails Domain Object Includes Class Attribute

I'm using a domain object to interface with a database in Grails.
When I use the list() method on a domain object to get all of the rows from a database it works great except for one thing. The object that comes back for each row also includes an attribute called "class". I've read some things about creating a custom marshaller that would allow me to remove that attribute from the object. Is that really the best way to not have to return the class attribute?
Thanks!
You can also use JSON.registerObjectMarshaller as below:
// BootStrap.groovy
JSON.registerObjectMarshaller( YourDomain ) {
it.properties.findAll { it.name != 'class' }
}
Refer here for a similar example.
Here's a link to change the way Grails renders JSON by default:
http://grails.org/doc/2.4.4/guide/single.html#defaultRenderers
Just change "NameOfDomainClass" to the class you want to render differently. In this case, the Domain Class.
import grails.rest.render.json.*
beans = {
bookRenderer(JsonRenderer, NameOfClass) {
excludes = ['class']
}
}

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 access a user defined Grails Project Package Name using the domain class string name

What we are attempting to do is create one grails application with multiple package names. Each package name will represent a different business entity and functionality.
Essentially multiple grails applications in one grails application project with each application being represented by having it's own package.
We will then like to uniquely prefix the tables based on the package name without having to prefix the domain class names or use static mapping on every domain class. The DefaultNamingStrategy works well with handling table prefixing on every domain class in the project.
The issue I am having is accessing the project Package name for each domain class name string that is called in the classToTableName method. For each domain class string that is passed to the classToTableName method, I need the user defined project Package name to differentiate what unique prefix should be assigned on the table based on the package name.
I have tried several different things in order to access the project package name using getArtefacts, or GroovyClassLoader, but the output is java.lang or the grails.commons package.
Any assistance that can be provide would be much appreciated. The CustomNamingStrategy class below has been created in the groovy folder of the project and is referenced in the hibernate section of the DataSource.groovy file.
class CustomNamingStrategy extends DefaultNamingStrategy {
String classToTableName( String className ) {
def packageName
def prefix = ""
// How do I access the package name of the domain class using className string?
if (packageName == 'recordretention'){
prefix = "Rr"
}
className = prefix + className
covertFromCamelCase(super.classToTableName(className))
}
String covertFromCamelCase(String input) {
GrailsNameUtils.getNaturalName(input).replaceAll("\\s", "_").toUpperCase();
}
}
After a lot of searching, it is the Holders class in grails 2.x that provides the access needed for classes in the src/groovy folder.
Class clazz = Holders.grailsApplication.domainClasses.find { it.clazz.simpleName == className }.clazz
packageName = clazz.getPackage().getName()
Untested but assuming that your class names between 'sub-applications' are different, you might be able to use grailsapplication lookup methods(untested getartefactbylogicalpropertyname) http://grails.org/doc/latest/api/org/codehaus/groovy/grails/commons/GrailsApplication.html#getArtefactByLogicalPropertyName(java.lang.String,%20java.lang.String)
You could lookup grailsapplication via applicationholder.

Redefine domain class mapping at runtime

I was wondering if there is a way in groovy to change the static mapping section of a grails class at runtime. As of now my domain class looks like this:
class Result {
ObjectId id
String url
def Result(){
}
void addObjectProperty(String key, value){
this[key]=value
}
//No constrains defined yet.
static constraints = {
}
static mapWith="mongo"
static mapping = {
collection "results"
database "test"
}
}
Now lets just say I want to change the mapping section at runtime to:
static mapping = {
collection "xyz"
database "mydb"
}
Now when I call save() on an object it saves the result to mydb in the collection xyz. I bet there is a way in groovy to accomplish just that but since I'm new to groovy I'm having a hard time here ... it would be nice if someone could point me into the right direction.
Thanks a lot...
Note my comment above about the wisdom of doing this. That said, you can replace your mappings at runtime with Groovy's metaclassing functionality.
Result.metaClass.'static'.mapping = {
collection "myCollection"
database "myDatabase"
}
In Grails, the mapping block is a Groovy closure, so you're free to replace it with any other closure object whenever you'd like. This may have crazy unpredictable Hibernate side-effects or do nothing at all, as I do not know when the mapping closure is used to configure Hibernate in the Grails app lifecycle.

Resources