why read-only access is writing to my db, in GORM? - grails

In my app, I have a code like this:
// 1
Foo.get(123).example = "my example" // as expected, don't change value in db
// 2
Foo.get(123).bars.each { bar ->
bar.value *= -1 // it's changing "value" field in database!! WHY?
}
note: Foo and Bar are tables in my DB
Why is gorm saving in database is second case?
I don't have any save() method in code.
Tks
SOLVED:
I need to use read() to get a readonly session.
(Foo.discard() also works)
Doc: http://grails.org/doc/latest/guide/5.%20Object%20Relational%20Mapping%20%28GORM%29.html#5.1.1%20Basic%20CRUD
(In the first case, I guess I made mistest)

Both should save, so the first example appears to be a bug. Grails requests run in the context of an OpenSessionInView interceptor. This opens a Hibernate session at the beginning of each request and binds it to the thread, and flushes and closes it at the end of the request. This helps a lot with lazy loading, but can have unexpected consequences like you're seeing.
Although you're not explicitly saving, the logic in the Hibernate flush involves finding all attached instances that have been modified and pushing the updates to the database. This is a performance optimization since if each change had been pushed it would slow things down. So everything that can wait until a flush is queued up.
So the only time you need to explicitly save is for new instances, and when you want to check validation errors.

Related

Grails do not commit after a successful service call

I'm performing the following logic on a single Service in grails 2.4.4.
class SampleService {
void process(params1, params2) {
SampleDomain1 sd1 = new SampleDomain1()
sd1.setProperties(params1)
sd1.save()
SampleDomain2 sd2 = new SampleDomain2()
sd2.setProperties(params2)
sd2.save()
}
}
What I understand is that Services are by default transactional. If sd1.save() is successful but sd2.save() is not, it will rollback the changes and will throw an error. While if both are successful, both are committed upon service's exit.
If my understanding is correct, then both of it should already been persisted to the database. However, the problem is: it does not— unless if you explicitly use the flush: true parameter based on my tests using the same set of params1 and params2.
sd1.save(flush: true)
SampleDomain2 sd2 = new SampleDomain2()
sd2.setProperties(params2)
sd2.save(flush: true)
}
Which, by the way is what I am really avoiding (what would be the point setting it as #Transactional). If that's the catch of Hibernate 4 / Grails 2.4, what do I need to do to make my services to commit at every end of a service call again? Do I need to configure any global configuration of Grails? I really need to flush my Domain classes at the end of every service automatically.
Note
I've already assured that the data is correct, including calling .validate() and other checker. Success in performing .save(flush: true) proves that. The problem I found is regarding to the update on Grails 2.4 on its FlushMode. Now, maybe what I really need is a global settings to override this.
If your data is not being flushed to the database layer there are some possibilities that come to mind.
There's some kind of error when trying to save to the database, you can try passing failOnError=true parameter to the .save() calls to see it clearly. (Actually setting this globally is a good idea since silently failing db calls are a migraine)
You are calling this service method from within the same service object. This will not allow the underlying spring declarative transactions to work due to the use of proxies.
You might have annotated some other method in the same service, in which case the default transactional support is no longer available for the remaining un-annotated (is this even a word?) methods.
You might have created the Service somewhere outside of service folder, not quite sure if this can cause an issue since I've never tried it out.
You have failed to sacrifice a goat to the Groovy and Grails Gods and they are messing with your head.
Edit :
I'm going to try to answer the points in your new edit.
Have you tried failOnError? It might be a issue that occurs when both objects are flushed to the DB at once, instead of manually committing them one at a time.
By figuring out a way to auto flush on save, you are going to be bypassing the transactions altogether AFAIK, now if I'm wrong then by all means go for it. But do test it out first before assuming.
Somewhere on my DataSource.groovy configuration, there is this line:
hibernate {
...
singleSession = true // configure OSIV singleSession mode
flush.mode = 'manual' // OSIV session flush mode outside of transactional context
^^^^^^^^^^
}
Which explicit states that every save should be flushed manually. As a solution, I comment out this line. After that, every database transaction now commits every time it exists a Service.

When does grails check for Object Staleness?

I'm using Grails 2.5.1, and I have a controller calling a service method which occasionally results in a StaleObjectStateException. The code in the service method has a try catch around the obj.save() call which just ignores the exception. However, whenever one of these conflicts occurs there's still an error printed in the log, and an error is returned to the client.
My GameController code:
def finish(String gameId) {
def model = [:]
Game game = gameService.findById(gameId)
// some other work
// this line is where the exception points to - NOT a line in GameService:
model.game = GameSummaryView.fromGame(gameService.scoreGame(game))
withFormat {
json {
render(model as JSON)
}
}
}
My GameService code:
Game scoreGame(Game game) {
game.rounds.each { Round round ->
// some other work
try {
scoreRound(round)
if (round.save()) {
updated = true
}
} catch (StaleObjectStateException ignore) {
// ignore and retry
}
}
}
The stack-trace says the exception generates from my GameController.finish method, it doesn't point to any code within my GameService.scoreGame method. This implies to me that Grails checks for staleness when a transaction is started, NOT when an object save/update is attempted?
I've come across this exception many times, and generally I fix it by not traversing the Object graph.
For example, in this case, I'd remove the game.rounds reference and replace it with:
def rounds = Round.findAllByGameId(game.id)
rounds.each {
// ....
}
But that would mean that staleness isn't checked when the transaction is created, and it isn't always practical and in my opinion kind of defeats the purpose of Grails lazy collections. If I wanted to manage all the associations myself I would.
I've read the documentation regarding Pessimistic and Optimistic Locking, but my code follows the examples there.
I'd like to understand more about how/when Grails (GORM) checks for staleness and where to handle it?
You don't show or discuss any transaction configuration, but that's probably what's causing the confusion. Based on what you're seeing, I'm guessing that you have #Transactional annotations in your controller. I say that because if that's the case, a transaction starts there, and (assuming your service is transactional) the service method joins the current transaction.
In the service you call save() but you don't flush the session. That's better for performance, especially if there were another part of the workflow where you make other changes - you wouldn't want to push two or more sets of updates to each object when you can push all the changes at once. Since you don't flush, and since the transaction doesn't commit at the end of the method as it would if the controller hadn't started the transaction, the updates are only pushed when the controller method finishes and the transaction commits.
You'd be better off moving all of your transactional (and business) logic to the service and remove every trace of transactions from your controllers. Avoid "fixing" this by eagerly flushing unless you're willing to take the performance hit.
As for the staleness check - it's fairly simple. When Hibernate generates the SQL to make the changes, it's of the form UPDATE tablename SET col1=?, col2=?, ..., colN=? where id=? and version=?. The id will obviously match, but if the version has incremented, then the version part of the where clause won't match and the JDBC update count will be 0, not 1, and this is interpreted to mean that someone else made a change between your reading and updating the data.

Breeze entity manager "hasChanges" property - how do I find out what is triggering the "true" state?

I have the following event handler in my datacontext:
manager.hasChangesChanged.subscribe(function (eventArgs) {
hasChanges(eventArgs.hasChanges);
});
and in Chrome I've set a break point on the "haschanges(eventArg.haschanges);" line.
The moment I load my app and the process of fetching data begins, this breakpoint is hit. It then proceeds to be repeatedly hit and the "hasChanges" property varies between "true" and "false" many times.
I know from further debug breakpoints that a simple query that "expands" a related table via its navigation property triggers a visit to my "hasChangesChanged" event handler.
What I don't know - as the "eventArgs" is so big and complex - is exactly which of my 5 or so related entities being retrieved is triggering the "true" on the "hasChanges" property. Is there a property within the eventArgs I can inspect to determine which current entity has caused the trip to the hasChangesChanged event handler?
I'm puzzled about why any of what I'm doing is setting "hasChanges" to true as all I do in the first instance is retrieve data. As far as I'm aware, nothing is changed whatsoever at the point the entity manager is convinced that something has changed.
To elaborate, my app prefetches lots of data used for a tree structure at the point where it is sitting waiting for first input from the user. As the user has not had an opportunity of touching anything in the app by this point, why would breeze think that any of the entities concerned have been changed when they've simply been read in from the database?
Use the EntityManager.entityChanged event if you want fine grained information about what has changed. This event gives much more detail but is fired much more often.
http://www.breezejs.com/sites/all/apidocs/classes/EntityManager.html

troubleshooting a NullPointerException in grails

preface note: I'm just starting to learn Grails, so I'm sure there are many other problems and room for optimization.
I've got two domains, a parent (Collection) and child (Event), in a one-to-many mapping. I'm trying to code an integration test for the deletion of children. Prior to the code in question, I've successfully created a parent and three children. The point where I'm having problems is getting a single child in preparation to delete it. The first line of my sample code is only there because of my rudimentary attempt to troubleshoot.
// lines 95-100 of my EventIntegrationTests.groovy file
// delete a single event
assertEquals("2nd Event", event2.title) // passes
def foundEvent = Event.get(event2.id) // no apparent problems
assertEquals("2nd Event", foundEvent.title) // FAILS (line #98)
foundEvent.delete()
assertFalse Event.exists(foundEvent.id)
The error message I'm getting is:
Cannot get property 'title' on null object
java.lang.NullPointerException: Cannot get property 'title' on null object
at edu.learninggrails.EventIntegrationTests.testEventsDelete(EventIntegrationTests.groovy:98)
What should my next troubleshooting steps be? (Since the first assertEquals passes, event2 is clearly not null, so at this point I have no idea how to troubleshoot the failure of the second assertEquals.)
This is not evident from the code: did you persist event2 by calling save()? Get will try to retrieve it from the persistent storage (the in-memory database for example) and if the event wasn't saved, the retrieved instance will be null.
If you did save it, did the save go through OK? Calling event.save() will return false if there was something wrong while saving the item (like a validation error). Lastly, you might try calling event.save(flush:true) in case the Hibernate session doesn't handle this case as you might expect (I'm not entirely sure about this one, but it can't hurt to try).
Try to print or inspect the event2.id on line 97 and check if you actually have an id, if so check if you actually get an Event object on line 97.
I dont think you saved the parent and its children successfully. after you save, you should make sure that every object that was persisted has a non null id, in your test.
What you are seeing is you created the event2 with a title, but didnt save it. It passes the first assertion because you created it. When you do the get, null is returned because your save failed.
in general for DAO integration tests i do the following
Setup -- create all objects Ill use in the test.
Save -- assert that all ids on saved objects are NOT null.
Clear the hibernate session -- this is important because if you don't do it, objects can be in the session from the previous operations. In your real world scenario, you are probably going to start with a find, i.e. an empty session. In other words, you are not going to start with anything in the session. If you are you need to adjust this rule so that the session in the test, when you start the actual testing part, is the same as the session of the code in the wild
Load the objects on which you want to operate and do what you need to do.

Why does my LINQ to SQL query fail the first time ("Row Not Found or Changed") and succeed the second time?

I'm using LINQ to SQL in ASP.NET MVC. I wrote some new code to update Orders in our system, and as far as I can tell it's exactly like a hundred other similar pieces of code I've written (grab the object, update some fields, submit changes).
This time though, when I try to run the update, I get a "Row not found or changed" LINQ exception on this call stack:
System.Data.Linq.dll!System.Data.Linq.DataContext.SubmitChanges(System.Data.Linq.ConflictMode failureMode) + 0x14c bytes
System.Data.Linq.dll!System.Data.Linq.DataContext.SubmitChanges() + 0x14 bytes
If I just refresh the page after the exception, it just works with no issues.
How can I get it to work correctly the first time?
I've seen answers on the net relating to DateTime precision and Update checks, but nothing about the submission simply working the second time, not the first.
My code is basically like this:
Order order = myDataContext.Orders.SingleOrDefault(order.OrderID == orderID);
order.Field1 = true;
order.Boolean2 = true;
order.Double1 = 300.0;
myDataContext.SubmitChanges();
The issue turned out to be that I was changing a related table in between fetching the Order, editing, and saving it.
When the related table was changed, the Order table was indirectly changed because of the parent-child relationship. That caused the change checking validation to fail.
All I needed to do is pull all the related code (fetch, change, save) into one tight block, with no other code in-between. I'm not having any problems now.
Your code looks fine.
There must be something else in myDataContext that is causing the problem.
Where is myDataContext defined? I am guessing that there is some code in a if is postback block, or something similar, to cause the code that runs to take a different path.
Are you creating a new datacontext when rebinding (after calling SubmitChanges)?
You should never reuse a datacontext for selecting, after performing insert/update/delete actions with it.

Resources