GORM read only columns - grails

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/

Related

Change Grails GORM format without dropping existing tables

I have one Grails application that has been running for a while. But now I want to change the GORM format and I wonder if there are simple ways to do so, i.e. ways that I don't need to drop existing tables, only modifying my application will do.
To be specific, I used to have one HashSet field that is mapped to varbinary in DB. There are some existing rows in this User table.
public class User{
//irrelevant attributes omitted
HashSet<String> friends=new HashSet<>();
static mapping={
friends sqlType: 'VARBINARY(10000)'
}
}
Now I've changed the field friends to a HashMap<String,Integer>. Now although I still map the field to varchar, Grails throws an exception every time I save an User object:
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
I first suspected that Grails keeps the old converting rule transforming HashSet to varbinary and it wasn't updated. So I tried changing the mapping from varbinary to blob and text, but neither worked.
I'm wondering if there are ways that I keep this column in varbinary in DB while letting Grails know that the attribute is now in HashMap and it should generate new ruls to convert.
Appreciate your insightful advice!
Edit: Im using Grails 2.4.4
There is one way I know of doing this: log into the database server so you have access to the database in a term window. Do this first on your development machine. Look at the relevant columns and see exactly which data types they use. Then, on your development machine, drop those columns and deploy the changed project. The new columns will be created if you've got the gorm set to 'update.' Again inspect the relevant columns and see if there's any way of changing the old columns (alter table...) in your production database to the new columns. You'll have to stop your production server, make the changes, deploy the new project and restart it. If you can't just change the columns you may have to create the new ones, move data over and delete the old ones - all with the application server stopped.

typo3 flow isDirty on model

Im trying to find out which attributes of an entity have been changed.
As far I have seen, there is a PersistenceSession with a method to check an object if an attribute isDirty. But its always true because it never registers the old object.
So if I take the demo from the QuickGuide and override the update method in the CoffeeBeanRepository:
/**
* #param \Acme\Demo\Domain\Model\CoffeeBean $coffeeBean
*/
public function update($coffeeBean) {
\TYPO3\Flow\var_dump($this->persistenceSession->isDirty($coffeeBean, 'name'), "name changed before");
parent::update($coffeeBean);
\TYPO3\Flow\var_dump($this->persistenceSession->isDirty($coffeeBean, 'name'), "name changed after");
}
... its always TRUE (both), despite I didn't change anything.
Anyone an idea/reference how this can be accomplished?
I am using it for a REST API where a user can't update several fields and on editing of some fields additional actions have to be executed.
The persistenceSession is part of the generic persistence backend of Flow and is neither maintained, nor really used unless you explicitly deactivate doctrine. Hence persistenceSession will not help you, because all entities are considered new for the persistenceSession as you noticed.
With doctrine you need to get the entity changeset from the "UnitOfWork", which you can get from an injected \Doctrine\Common\Persistence\ObjectManager. See also Is there a built-in way to get all of the changed/updated fields in a Doctrine 2 entity
However, this is a suboptimal solution and a hacky work-around at best. If you need to track changes to your entity, it should be an explicit part of your domain model. For example make your setters record a changed properties list, when the given value is different from the current.
When done, you could even optimize doctrines change tracking on the way with that: http://doctrine-orm.readthedocs.org/en/latest/reference/change-tracking-policies.html#notify

NHibernate - Updating only specified object properties identified at runtime

I'm trying to implement a very granular security module in an ASP.NET MVC 3 app where only certain users can edit certain columns on records in a table. I can imagine that the update SQL statement's list of columns would only include the columns that the user had the right to change. The thing is, I'm planning to use an ORM like NHibernate. I'm wondering if NHibernate provides a way to determine at runtime which properties of a model should be part of an Update. Or is my only option to, on the POST method, get the model again from the database, set only the properties that the user is allowed to set then finally Save the model. Also, is this a good way to handle my requirement of of granular security?
Would dynamic-update and dynamic-insert be enough?
dynamic-update (optional, defaults to false): Specifies that UPDATE SQL should be generated at runtime and contain only those columns whose values have changed.
dynamic-insert (optional, defaults to false): Specifies that INSERT SQL should be generated at runtime and contain only the columns whose values are not null.
Otherwise it might be possible with events or interceptors, but I've never used them so I don't know exactly.

Grails Gorm Partial Save

I have a very basic question in saving objects which I get from a client sent via JSON.
I have a customer object which is transfered to the client, after editing the customer its send back to Grails and needs to be saved in the database. For performance I am not sending the complete customer object over the wire.
The problem is now if I want to store the customer object Grails validates of course the relationships of the customer object and fails. This is OK because I havent sent the relationsships.
My question is now how do I solve this problem now? Do I need to query the database again with the customer id and update the edited properties or is there a more elegant way? This looks a little bit expensive from database perspective as I need to read the database each time when storeing an object. As well from code perspective I need to check which properties are set and update them.
Thank you!
You cannot use save() for doing partial update, since grails cannot guess what fields you actually want to update: Maybe you REALLY want to set a field-value to NULL, so Grails cannot just ignore those fields. So I see two options:
Do it like you have described: Load the instance from DB, set the values and save again. You have mentioned, that you do not like to care what fields are updated, and you just want to take all attributes of your JSON instance. So assuming your already parsed JSON-instance is called jsonInstance and your database version of the customer is customerInstance, you can do:
jsonInstance.properties.each { field ->
customerInstance."${field.key}" = field.value
}
However, note that there are security limitations (if an attacker injects an 'id' attribute or other relevant attribute values into it, those will be just overwritten).
Use executeUpdate-function, see:
http://www.grails.org/doc/latest/ref/Domain%20Classes/executeUpdate.html
I think, if you really want to save performance, then go like this. However you have some hardcoded DML, which will cost maintainability and flexibility.

Enityframework - ConcurrencyMode where clause

Reading up on the web I can set ConcurrencyMode=Fixed against a entity framework database field.
My understanding is that any update statements include in its where clause the original values to determine if the datacontext has changed.
(So if rows effected gets a hit then all is good otherwise we have a conflict )
Now my question is..
Do only the columns changed in the
datacontext get included in the where
clause or all columns that are
marked as fixed.
i.e.
(If I have the following setup)
name=fixedconcurrency
DateofBith=fixedconcurrency
NI=fixedconcurrency
When only the name field changes would I get:
update tbuser set name="newJason"
where Id=2 and name="oldJason" and
DateofBith="19/10/1970" and NI=1234566
or
Update tbuser set name="newJason"
where Id=2 and name="oldJason"
My goal is to only have conflicts raised when a user overwrites another users data ( At field level not record level).
A snippet from MS says that entity framework will only update the fields that a user has edited. IF all fields are included in the where clause it would make this statement redundant.
Thanks,
Jason
All of them. The intention of the feature is for something like a TIMESTAMP field, which the user cannot assign directly.

Resources