4
votes

We are using Grails 2.2.1 and are seeing an issue when we try and perform a CRUD operation on a domain class that is tied to multiple datasources.

Here is what our static mapping looks like and the results of some operations:
In this scenario the CAR table only exists in d2.

class Car {
   static mapping = {
      datasources(['d1','d2'])
   }
}

Car.d2.listAll() //This code works and return data from d2
carObject.d2.save() //This code fails with a Table or View does not exist

Now if I add the table to d1

class Car {
   static mapping = { 
      datasources(['d1','d2'])
   }
}

Car.d2.listAll() //This code works and return data from d2
carObject.d2.save() //This code now works and inserts a row into table in d2

So it seems when you have multiple datasources the table has to exist in the first one you have listed, does anyone know a way around this?

UPDATE 10/27

I have tried injecting the actual datasource and using it to perform the CRUD operations as a workaround. Unfortunately grails does not allow you to use an injected datasource to specify where you want your changes to go.

Link: How to use injected dataSource in Grails to perform operations?

Issue seems to be worst than originally anticipated. Not only does the table have to exist in the first datasource listed, but it seems to be checking the data as well. It will not allow me to insert a record into d2 with a key that exists in d1.

UPDATE 2 10/27

After researching it seems that the validation is being run against the first dataSource listed, then the actual operation is being performed on the dataSource specified.

It now works if i pass in validate false:

carObject.d2.save(validate:false) 

The only problem with this work around obviously is that I lose the validation.

1
Why do you want both datasources listed in the mapping if the table isn't there? - Jeff Beck
So in reality we have 6 datasources that the table could exist in. Throughout the lifecycle of the app being in the production env however the table may not be in all 6. We also don't want to have to push a new war file to add in the datasource whenever the table is pushed to a different environment in production. - southpaul
I don't understand why the .listAll() works fine but the CRUD operations have an issue with this. - southpaul
Can you call validate on the datasource carObject.d2.validate() ? Also this sounds like a bug in gorm you may want to open a ticket. - Jeff Beck
Hi, do you have a solution now ? I mean to make it work with carObject.d2.save(validate:true) . Do not lose the validation. - Yaroslav

1 Answers

0
votes

I've tried to create new session for session factory bean. And after this do object.save(). Looks like it works. See example:

def ctx = grailsApplication.mainContext

        ctx.getBeanNamesForType(SessionFactoryImplementor.class).each {

            SessionFactoryImplementor sfi = ctx.getBean(it)
            GrailsSessionContext gsc = new GrailsSessionContext(sfi)

            if(!TransactionSynchronizationManager.getResource(gsc.sessionFactory)) {
                def newSession = gsc.sessionFactory.openSession()
                def sessionHolder = new SessionHolder(newSession)
                TransactionSynchronizationManager.bindResource(gsc.sessionFactory, sessionHolder)
            }
        }