Redefine domain class mapping at runtime - grails

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.

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']
}
}

How to override the DomainClass.list() in GORM (Grails)

People, I'm facing a problem with grails GORM, my Application is totally dependent of the DomainClass.list() method, it is in all of my create/edit GSPs, but now I need a particular behavior for listing objects. Being more specific I need to filter these lists (All of them) by one attribute.
The problem is I'm hoping not to change all the appearances of these methods calling, so is there a way to customize the behavior of the default list() method ? I need it to function just the way it does, but adding an ending filter.
Maybe you can use hibernate filter plugin (see here). This will allow you to filter all finder methods (including list()) based on a property:
static hibernateFilters = {
enabledFilter(condition: 'deleted=0', default: true)
}
Have you considered using names queries? You could always do something like this:
class DomainClass {
// ... class members
static namedQueries = {
myList { params->
// put your complicated logic here
}
}
}
Then you can just replace your calls to DomainClass.list() with DomainClass.myList.list().

grails - tell me if anything is dirty?

Grails provides an isDirty method that can be called on domain objects. How would one modify the Grails domain model system, such that one could simply call a method, to find out if any domain objects are dirty.
I'm struggling with some "unsaved transient instance" errors that I haven't been able to nail down, and it'd be great to know what's dirty. Is there an elegant way to do this with groovy?
Add this to BootStrap.groovy:
import org.hibernate.Session
Session.metaClass.isDirty = { ->
delegate.persistenceContext.entitiesByKey.values().any { it.isDirty() }
}
This adds an isDirty() method to Hibernate sessions that checks that top-level instances or instances in collections are dirty and you can use it with withSession, e.g.
boolean dirty = SomeDomainClass.withSession { session -> session.isDirty() }
or if you have access to the sessionFactory bean (e.g. from a def sessionFactory dependency injection)
boolean dirty = sessionFactory.currentSession.isDirty()
Based on Burt's answer, one might also do:
Session.metaClass.whatsDirty = { ->
def everythingDirty = []
delegate.persistenceContext.entitiesByKey.values().each { if (it.isDirty()) everythingDirty.add(it) }
return everythingDirty
}

Prefix column names in GORM

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

Resources