I'm using Hibernate 3 and Grails 2.2.5.
I have an AJAX call in one of my views that is supposed to look up some data and provide a text result. In the methods used to generate the text result, I have a method call to a service to save the text result to its own domain.
The problem is that the .save(flush: true) will not persist to the database. However, if I add a Groovy SQL instance and perform an .executeInsert() with any insertion the insert in the Groovy SQL will be inserted AND the .save(flush: true) method will work as expected... I've tried various different ways, but as soon as I comment out the .executeInsert("...") the domain class will not be persisted.
I've checked common problems: validation checks out (returns true), I turned deepValidate to false and I used flush in case Hibernate was trying to save the insertion statement to a later time. I also turned on logSql = true in DataSource.groovy and the SQL insert statement does get logged when I comment the .executeInsert("...") out but is never persisted to the table.
-EDIT/UPDATE-
The Hibernate log has the insert statement as:
insert into TextDomain (version, text, ... , id) values (?,?,?,?,?)
Are the question marks supposed to be there? Not too experienced with Hibernate so I'm not sure if that's the actual SQL statement it is executing or if it is filling the values in?
Also, the method I'm trying to call .save() in is in src/groovy .
EDIT/UPDATE -> TEST:
I setup a test as a single action in a controller. I simply called a service method that filled the textDomain with some test values and then did a .save(). When calling the controller action (i.e. going to the url my-app:8080/test/text) the textDomain is persisted correctly. However, I tried adding the service that has the actual textDomain instantiation and test values from another service and it will not persist...
Related
If I use a GORM domain object in my Grails command object, the command object commits changes to the domain object automatically, even though I did not call the save() method.
I want to bind to GORM objects in the command object but without saving or committing changes to the database. If my controller or my service throw an exception, I want transaction rollback.
I can force the behavior I want with the following annotations, but that feels like I'm doing it the hard way.
Controller Class = #Transactional(readOnly = true)
Controller action method = #Transactional
Command Object Class = #Transactional(readOnly = true)
Service Class = #Transactional
Am I doing something wrong, are Grails domain objects supposed to get committed automatically by the command object unless I add all these annotations?
This isn't specific to command objects, it's a general feature of controller actions. By default the open-session-in-view pattern is active, where a Hibernate Session is created and bound to a thread-local before the action runs and it's flushed and closed after the action finishes. Any persistent instances retrieved from the database (either explicitly because of a query, or implicitly during data binding) will stay attached to the open session and are dirty-checked when the session flushes. Any modified instances will have their changes flushed along with other queued actions with or without a save() call.
Making the entire method (or class) transactional and read-only is probably overkill. A more direct approach would be to either retrieve instances as read-only, e.g. using read() instead of get(), calling the readOnly method when doing criteria queries, etc., or 'detaching' modified instances by calling the discard() method on each. Another option is to clear the session at the end of the action so there's nothing to automatically flush, e.g.
AnyDomainClass.withSession { it.clear() }
Note that instances retrieved in 'read-only' mode can have their changes persisted, but Hibernate won't automatically do anything for those instances, it only happens when you explicitly call save().
Most of our tables have one or more columns which are set by the database, either by a trigger, or we want to use the database default value (which requires not sending the field at all in the insert or update)
This includes transaction dates set in the dB (so all the times are times stamped very accurately by a single source, not relying on the accuracy of the time on an arbitrary server or pc.)
The second VERY common use case is say if a customer record has his address and a last logged in field. the last logged in field (and number of failed logins) is set by another part of the system (e.g. by a web site server). The current overly simplistic CRUD system which GORM provides would overwrite such a field when an operator or customer edits their address for example. This is because GORM includes in its update and insert statements every field, even if it's null, or if it has not been changed.
We need a way to scrub the field from inserts and updates, but still have it used in the read calls.
I.e. a true "read only" attribute.
We tried this:
failedLogins editable: false, attributes: [readonly:true]
Which has no effect on the SQL generated (and doesn't even affect the scaffolded UIs - its still editable in create and edit, in grails 2.4.4 at least, but thats another story)
When we do want to explicitly write one of these fields, such as number of failed logins, we would resort to using embedded SQL.
I saw this post: Read-Only columns
Which asks exactly the same question, but only gives one solution, which is this plugin:
extended GORM mappings
Unfortunately, this plugin has not been updated since 2010, and only works with 1.3. We need something which works with 2.4.4.
Any grails app which has multiple systems which edits independent fields needs something like this, or to do extensive locking (Which is usually out of the question).
E.g. an operator opens the customer details for editing, edits something editable (e.g. address), then the operator fails a login on the website (a different grails or non-grails app), then the operator saves the player details. If the saving included the numberOfFailedLogins field, the system would fail. If opening the player details for editing locked the player, then the player would not be able to login, as updating the "lastLoggedIn" or "numFailedLogins" would fail to be able to write due to the lock. The solution is VERY simple - read only columns. Another way would be to put each read only type field in their own tables, but this would be untenable (and result in hundreds of one field tables)
Or we go back to using MyBatis, which has no such issues, and full control. Sadly, there is no good mybatis plugin for grails.
You can use derived properties for string and number properties:
class Batch {
String name
Integer timesRun
static mapping = {
timesRun formula: 'times_run' //times_run is a column in the "batch" table
}
}
In the code above, timesRun would be read in from the database but ignored in inserts and updates as Hibernate considers the column a calculated one.
Updated the example because the original one may have been misleading
This probably doesn't specifically answer your question, but you can use dynamicUpdates to tell GORM to only update the properties of the domain object that have changed during the current session. So as long as you don't change the "read-only" property in your code it won't be set in the SQL update statement generated by Grails. For added safety you could override (and noop) the setter so that your code can never change that property.
https://grails.github.io/grails-doc/latest/ref/Database%20Mapping/dynamicUpdate.html
One of the downsides of dynamicUpdates is that it might make the Hibernate query cache less useful. However, it seems that some Grails/Hibernate experts recommend that you disable the query cache anyway (at least in older versions of Grails). Not sure if that's true of Grails 2.4+
http://grails.github.io/grails-howtos/en/performanceTuning.html
http://www.anyware.co.uk/2005/2012/11/12/the-false-optimism-of-gorm-and-hibernate/
http://tech.puredanger.com/2009/07/10/hibernate-query-cache/
I'm using Entity Framework (DbContext with database first) with MVC. When user save from a form, I have a condition in the controller that send the entity to the update of insert method depending of some internal flag of mine.
When sending entity to the update method, I flag it to modified using context.Entry(myEntity).State = EntityState.Modified;, I call saveChanges() and everything work well.
When sending the entity to the insert method, I flag it to added using context.Entry(myEntity).State = EntityState.Added; but when calling saveChanges() I receive error about 2 fields that are required...
The problem is that thoses 2 fields are not empty and they effectively contain valid data just before saving... I have even try to force new values to thoses 2 fields just before saving but same error.
It may be usefull to mention that I'm using Devart DotConnect For PostgreSQL as db provider.
Any idea how to debug this problem?
EDIT:
Here is the error:
Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
When looking for this EntityValidationErrors I receive the 2 following specific errors:
The flg_actif field is required
The user_creation field is required
As mentionned before, those fields are filled with data just before saving so I don't understand what is happening.
I'm using EF v4.0.30319 (system.data.entity=> v4.0 and EntityFramework=> v4.4)
EDIT2:
Just to clarify a little bit more: The entity I'm trying to insert already exist in database. The form show the data of this database row. When saving, I decide if I update the row (this work well) but sometime, I need to insert the edited row as a new register instead of updating it to keep an history of the change in database.
Could you verify if the EntityKey property is set or null on the items you are trying to save?
If it already has a key, the context is already aware of the item, and you should use Attach instead of setting the state to added manually.
EDIT: To summarise the point from below. It looks like what you are doing is inserting a new copy of a row already associated with a context. That is almost certainly your problem. Try creating a fresh object based on your original row (i.e. copy the variable values or use a copy constructor), then add that new object.
Additionally, you should not need to set the state manually on a newly added object. You are trying to force the state here because the context doesn't see that item as a new one.
How do I use the GORM .get to retrieve an object o, modify some fields, and call o.validate() to find errors without Hibernate saving the object to the DB. discard by itself does not prevent the save. Neither does
clazz.withTransaction { status ->
row.validate(flush:false)
row.discard()
status.setRollbackOnly()
}
This post recommend using a command object but this code will apply to many different domain object. There must be a simple way (some parameter passed to validate?) to give Hibernate the do not save instruction. Do I need to create a new instance every time?
If you use read() instead of get() to retrieve the object it won't be auto-saved during a flush (e.g. at the end of a transaction or a web request). It's not truly read-only, since you can call save() and it will persist - it's just not going to auto-save when dirty.
My application is using EF code-first design and all generally works very well.
Via a private configuration file, I can specify how I would like EF to handle changes to the db schema, and so create/recreate the relevant tables as desired - the options are "never" "create", "always", "onSchemaChanged" and (for the future) "onSchemaModified".
This works well - but I am getting lost in a couple of places .....
During development, I would like to use the hook as described in
"Database in use error with Entity Framework 4 Code First" - but this seems to execute on EVERY run of my program"
public void InitializeDatabase(Context context)
{
context.Database.SqlCommand("ALTER DATABASE Tocrates SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
_initializer.InitializeDatabase(context); // Maybe this does nothing if not needed
context.Database.SqlCommand("ALTER DATABASE Tocrates SET MULTI_USER")
}
So .. to real my question: Is there an override that I can use to detect whether EF will ACTUALLY be trying to modify the database, so I can set this SINGLE_USER stuff when needed? And if so, can I detect the reason EF it is doing so (see my list of options above) so I can log the reason for change?...
All help and suggestions are very much appreciated.
Unless you have set the database intializer to null initializers run always once (per application lifetime) when you are using a context for the first time. What then actually happens depends on the initializer (your inner _intializer):
For DropCreateDatabaseAlways and CreateDatabaseIfNotExists it's clear by their name what they do.
For DropCreateDatabaseIfModelChanges there is only the question if the model changed or not. EF detects this by comparing a model hash with a hash stored in the database. You can check this yourself by calling...
bool compatible = context.Database.CompatibleWithModel(true);
...within your custom InitializeDatabase and then decide based on the result if you want to send your SqlCommands or not. (Don't call this with a self-created context because it will cause the database to be intialized first before the model compatibilty is checked.) The parameter bool throwIfNoMetadata (which is true in my example) causes EF to throw an exception if the model hash in the database does not exist. Otherwise the method will return true in that case.
For a custom inner initializer: Whatever your code will do.