Updated post:
In a Controller if I do this:
def obj = new Test(name:"lol")
obj.save(flush:true)
obj.name = "lol2"
//a singleton service with nothing to do with obj
testService.dostuff()
/*
"obj" gets persisted to the database right here
even before the next println
*/
println "done"
Can anyone please explain me why is this happening with Grails 1.3.7 and not with Grails 2? What is the reason?
I know I could use discard() and basically restructure the code but I am interested in what and why is happening behind the scenes. Thanks!
Old post:
I have a test Grails application. I have one domain class test.Test:
package test
class Test {
String name
static constraints = {}
}
Also I have a service test.TestService:
package test
class TestService {
static scope = "singleton"
static transactional = true
def dostuff() {
println "test service was called"
}
}
And one controller test.TestController:
package test
class TestController {
def testService
def index = {
def obj = new Test(name:"lol")
obj.save(flush:true)
obj.name = "lol2"
testService.dostuff()
println "done"
}
}
So what I do:
Create a domain object
Change one of it's properties
Call a singleton service method
What I would expect:
Nothing gets persisted to the db unless I call obj.save()
What happens instead:
Right after the service call Grails will do an update query to the database.
I have tried the following configuration from this url: http://grails.1312388.n4.nabble.com/Turn-off-autosave-in-gorm-td1378113.html
hibernate.flush.mode="manual"
But it didn't help.
I have tested it with Grails 1.3.7, Grails 2.0.3 does not have this issue.
Could anyone please give me a bit more information on what is exactly going on? It seems like the current session has to be terminated because of the service call and because the object is dirty it is getting automatically persisted to the database after the service call. What I don't understand that even with the manual flush mode configuration in Hibernate does not help.
Thanks in advance!
I'm not sure what about that thread you linked to made you think it would work. They all said it wouldn't work, the ticket created has been closed as won't fix. The solution here is to use discard() as the thread stated.
Related
Starting with a github repo that demonstrates how to use GORM outside of Grails, I am attempting to use dynamic finders so that I can look up a particular domain object by one of its properties. In this example, we have this person object in groovy as such:
package domain
import grails.gorm.annotation.Entity
import org.grails.datastore.gorm.GormEntity
#Entity
class Person implements GormEntity<Person> {
String firstName
String lastName
static mapping = {
firstName blank: false
lastName blank: false
}
}
Now lets say I want to look up a person by last name. I should be able to use the GORM-enhanced Person entity method findByLastName. I'm able to compile the code that attempts this, but when I call it at runtime, the method is not found.
I added a test method to PersonSpec.groovy that looks like this:
#Rollback
def "person can be found by last name"() {
when:
def p = new Person(firstName: 'Scott', lastName: 'Ericsson')
p.save(flush: true)
def foundPerson = p.findByLastName('Ericsson')
then:
foundPerson.firstName == 'Scott'
}
I get this error when the test is run:
domain.PersonSpec > person can be found by last name FAILED
groovy.lang.MissingMethodException at PersonSpec.groovy:32
The test method above it creates and saves a person record successfully, so some aspects of GORM functionality are working. But dynamic finder functionality is not being properly applied at run time, even though the compiler thinks everything looks good.
My entire build.gradle is this:
apply plugin: 'groovy'
repositories {
jcenter()
}
dependencies {
compile "org.hibernate:hibernate-validator:5.3.4.Final"
compile "org.grails:grails-datastore-gorm-hibernate5:7.0.0.RELEASE"
runtime "com.h2database:h2:1.4.192"
runtime "org.apache.tomcat:tomcat-jdbc:8.5.0"
runtime "org.apache.tomcat.embed:tomcat-embed-logging-log4j:8.5.0"
runtime "org.slf4j:slf4j-api:1.7.10"
testCompile 'org.spockframework:spock-core:1.1-groovy-2.4'
}
Does anyone know what I am missing?
So I've been struggling with this for a couple of days, and wouldn't you know as soon as I post the question I figure it out almost instantly. It's simple--I need to use findByLastName method statically on the Person object instead of a person instance. The code that works in PersonSpec looks like this now:
#Rollback
def "person can be found by last name"() {
when:
def p = new Person(firstName: 'Scott', lastName: 'Ericsson')
p.save(flush: true)
def foundPerson = Person.findByLastName('Ericsson')
then:
foundPerson.firstName == 'Scott'
}
I've got a strange issue when trying to cache a method call on a 'repository' object in Grails (2.1.5). This repository, a plain groovy object in src/groovy, combines data from two data sources and returns a 'Seller' object.
def aDatabaseHelper
def bDatabaseHelper
#Cacheable('seller_do_get')
public Seller get(id){
....
//do stuff with aDatabaseHelper and bDatabaseHelper
return seller
}
The SellerRepository is defined in resources.groovy
aDatabaseHelper (ADatabaseHelper ){
aDataSource = ref("dataSource_a")
}
...
sellerRepository(SellerRepository){
aDatabaseHelper = aDatabaseHelper
bDatabaseHelper = bDatabaseHelper
}
And we've got ehcahce plugin (1.0.0) installed and working fine for other objects/methods.
The above for some reason doesn't cache it - it goes inside the get method each time. I created a 'BlaRepository' which takes in the same dependencies and has a getBla(id) method and it is getting cached just fine.
Does someone has a clue what's going on here? Which silly mistake am I making?
Seems like it should work, but could be a bug. Create a small test app that demonstrates the problem and run grails bug-report and attach it to a JIRA at http://jira.grails.org/browse/GPCACHEEHCACHE and I'll take a look.
I am using Grails 2.2.1, and I have a custom dataSource injected into the service so that I can execute some SQL queries.
Upon first execution, there is a dataSource, but on each subsequent call, the reference to the dataSource has become null.
class ReportService {
def dataSource_myds
Object[] reportRecords(int a) {
String query = "SELECT ..."
Object[] resultSet;
Sql sql = new Sql(dataSource_myds)
// ^ Here the NullPointerException is thrown
// But it always works at the first execution
sql.eachRow(query, [a]) {
...
resultSet += result
}
return resultSet
}
}
class ReportController {
ReportService reportService
def report = {
...
Object[] resultSet1 = reportService.reportRecords(1)
...
Object[] resultSet2 = reportService.reportRecords(2)
// ^ java.lang.NullPointerException : Must specify a non-null Connection
...
}
}
Has anyone ever seen this before, and if so, how can I avoid this?
Here is my DataSource.groovy
environments {
development {
dataSource_myds {
url = "jdbc:oracle:thin:#..."
driverClassName = "oracle.jdbc.driver.OracleDriver"
username = "..."
password = "..."
}
}
}
Try, to use resources.groovy way as well. This will also give you option for environment basis datasource.
Explained well on the link given below:
Grails 2 multiple dynamic datasources in services
Thanks
Solved avoiding 2 subsequent calls to the service. It seems the framework nulls the service connection after the first call from the controller.
James Kleeh's comment solved it for me - grails clean and then restart the app.
I had a similar issue and I got it fixed. Firstly, make sure your Service class is in the grails-app/services folder. Secondly, you need to make sure you get the object of the service class using the injection mechanism and not by using the constructor. I had my service class in the right folder but I was trying to create the instance of the service class as MyService.instance in my controller and having the issue of null dataSource/connection. Then I tried def myService in my controller instead of MyService.instance and it worked. Hope this helps. Thanks
I am trying to store an instance or at least id of each domain that is auditable. For example, there is a domain 'Student' and is auditable. So, whenever the domain an instance of domain is created or edited, a new record is stored in audit log. What I want is to store the id of each domain that is saved or updated. How can it be done ?
Thanks in advance
You can use Grails Envers plugin that uses Hibernate Envers underneath. Plugin information can be found on plugins site here.
You can better refer to the url: http://grails.org/plugin/audit-logging
The above plugin works well for the domain class without collection, in case if you using collections in domain class, refer this stackoverflow link: How to determine Collection changes in a Hibernate PostUpdateEventListener?
Hope it will help a lot
I Wouldn't use the audit plugin , it has some issues when running your tests. This plugin in was created when the GORM didn't provide support for events. You can intercept the following events
beforeInsert - Executed before an object is initially persisted to the database
beforeUpdate - Executed before an object is updated
beforeDelete - Executed before an object is deleted
beforeValidate - Executed before an object is validated
afterInsert - Executed after an object is persisted to the database
afterUpdate - Executed after an object has been updated
afterDelete - Executed after an object has been deleted
onLoad - Executed when an object is loaded from the database
Hope this helps
You can use events with AuditLog plugin like below and then add what ever you would like too. Hope this makes sense
def onChange = { oldMap,newMap ->
println "Person was changed ..."
oldMap.each({ key, oldVal ->
if(oldVal != newMap[key]) {
println " * $key changed from $oldVal to " + newMap[key]
}
})
}
def onSave = {
println "new datainserted"
// may optionally refer to newState map
}
In any of these methods we can use
def event = new AuditLogEvent(
actor: actor,
className: className,
eventName: eventName,
persistedObjectId: objectId,
propertyName: propertyName,
newValue: newValue
)
if (event.validate()) {
auditLogListener.saveAuditLog(event)
log.info "Logged audit event [$event]"
}
I'm trying to call a method on a grails service from a controller, but it looks like execution is just skipping the method call.
I've tried debugging the application with a breakpoint inside the method but it is never hit.
My service (generated with grails create-service) is:
class FormatterService {
static transactional = false
def formatList (List<Host>, String fmt) {
OutputObject somePOGO = new OutputObject();
(snip)
return somePOGO
}
}
Then on my controller I have:
class HostController {
def formatterService
def getHostsByLabels = {
(snip)
OutputObject o = formatterService.formatList(someHosts,params.format)
(snip)
}
}
When the formatterService.formatList method should be called in the controller, execution simply skips to the next line, no output is printed to the console and breakpoints within the method are not hit. The OutputObject o reference is null afterward.
What is wrong here? It could be a really basic mistake from my part, but I just can't put my finger on it...
To Me it seems a MetaProgramming Disaster..
Well there are 3 Tests to Debug:
_1) first try to do
println formatterService
println formatterService.getClass()
just to check if its injected bean is the desired one, some plugins sometimes inject beans which overrides the default.
_2) Make sure that the method with a name "formatList" is not injected in your services through metaprogramming by any plugin or core code.
How to test this is simple: Just change the name of the method to some Unrealistic One, ex: "formatListabcdewdw" and then call that one. If it works then its method overriden issue.
and if you are more enthusiastic you can see the metaMethods by
println formatterService.metaClass.methods
_3) just try to do "params.format as String" as the last argument in the method call.\
.
Hope any of these helps, please Do let me know of the findings, i am curious to know.. :)
I found the issue. It has to do with the method signature.
Printing out the thrown exception's message, it says:
No signature of method: hms.FormatterService.formatList() is applicable for argument types: (java.util.TreeSet, java.lang.String) values: (...)
Possible solutions: formatList(java.util.List, java.lang.String)
So, a rookie mistake (wanting to pass a TreeSet for a List) aided by weak typing in Groovy... :P
I've changed the method signature to
def formatList ( items, String fmt) {
and call it as
def activeHosts = ...
OutputObject o = formatterService.formatList(activeHosts, params.format as String)
and now it works.