grails domain id as int or Long - grails

Hi I have a domain class that I set as int userID. Will it affect when the auto number become very big that User.findById() throws error? If I change to Long now (people are already using the application) will it affect the findById()?

findById() will work just fine.
The real problem will be when inserting new data into a table, if the id is auto-generated, it, most probably, will restart when reaching the max value which can result in duplicate ids, and hence, errors.
In general, is not that easy to alter the schema definition when the app is already in production and the DB is populated. And if you try to do that in Grails, you have the risk of losing information in the DB. So please, do a backup, before trying anything.

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.

GORM read only columns

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/

"CoreData does not support persistent cross-store relationships" despite matching x-coredata ids

When saving a Core Data managed object context on iOS 6.0.1 to a SQLite store, I run into a strange "CoreData does not support persistent cross-store relationships" exception. It concerns a one-to-one relationship between Quotes and AbstractSources in the model. At runtime it concerns a Quote and a Book (where Book inherits from AbstractSource. All works well in the model editor.)
I've researched similar reports and covered the reported causes:
I am assigning both the Quote and the Book to the same persistent
store using assignObject:toPersistentStore:, so neither remains
unassigned.
The error description shows that all "absolute" x-coredata ids start
with the same prefix (e.g.
"x-coredata://82B3BEB3-60F2-4912-AC80-11AAD29CFF99/", so there
really seems to be one store only in use.
My questions are these:
Is there anything else I have to check (perhaps sg. in relation to
AbstractSource, which I do not touch/control in my source? I am
creating both the Quote and the Book with a call to
initWithEntity:insertIntoManagedObjectContext each.)
I noticed that the error description also includes several
"relative" x-coredata ids (of the form "x-coredata:///..."). Could
it be that the absolute form is always considered as
"cross-database", even if "absolute" prefixes (see example above) are the same?
And if so, how could I influence any choice between "absolute" and
"relative" x-coredata ids?
Thx (much) for your attention!
So this is what had (presumably) caused the trouble:
My managed object context's coordinator has to manage two persistent
stores. Now the one to which I assigned Quote and Book and were I
wanted them saved is reset at start-up. There was a bug
in this code, which rendered this store unusable. Since a second one
was available it silently took over, in this case leading to unwanted results.
Lesson: I now assert that there are/remain indeed two stores after setting up the core data stack.
During earlier development of my Core Data model, I had renamed some
of its entities in the model editor. By mistake I had only changed
names, but not the entities class properties. So in effect while
everything worked well in the model editor, by-then-unexpected
classes were used at runtime, and therefore unexpected classes where
assigned to unexpected/wrong stores as well. Lesson: I now make sure
that entities names and their class properties remain in perfect sync (other
circumstances permitting).
The issue is now resolved, and I've also refactored my code/model to use (non-overlapping) configurations instead of explicit assignments, which should also help going forward.
Again, thx for your attention

Retrieving autogenerated data in insert on ADODataset

I actually try to do an insert on a ADODataset linked on a table with an auto-generated GUID.
When I try to get the new ID of my record I get some zero for GUID.
This is an old question but if anyone comes across it...
The big advantage of using GUIDs is that you don't care where they originate from. A value generated as part of a default constraint is no better or worse than a correctly generated GUID in a client program.
#Ravaut123 is correct in that you should just set the GUIDs value when inserting on the TADOataSet set

Entity Framework doesn't update data value changes made from database

I didn't know quite how to word this. I have an ASP.NET MVC 3 web application with a pretty standard EF 4.1 code first with existing database (non-auto-generated) repository pattern. There's a context which is under a dataservice the web app talks to.
The problem I have is this: say I have a database table with an integer column. The value is 10. If I go into the database itself and enter 25 into the table, no matter how many times I hit refresh on the browser, close the browser and reopen it, clear the browser history, etc, it still persists the value of 10. I have to republish the site.
Why does it do this? Am I blaming the right thing here? Is this an EF problem? an ASP.NET problem? Server problem? ... I don't know where to look into this.
Yes, I've struck this problem in my own applications.
The "entities" (object instances) tracked by Entity Framework are cached in memory, and aren't updated when you requery the database, in case overwriting them would clobber any changes you've made to the cached version.
You can get around it by forcing EF to overwrite existing values, but be aware that this will overwrite anything you've changed, so only do it if you know you've saved any pending changes first.
I've written this extension method to do the job:
public static class DbSetExtensions
{
public static System.Data.Objects.ObjectSet<T> Uncached<T>(this IObjectContextAdapter context)
where T : class
{
var set = context.ObjectContext.CreateObjectSet<T>();
set.MergeOption = System.Data.Objects.MergeOption.OverwriteChanges;
return set;
}
}
So using that, I can say:
var orders = myDbContext.Uncached<Order>().Where(...);
... and the orders set will contain orders that are fresh from the database, overwriting the properties of any Order objects previously queried.

Resources