Details
-
Type:
Bug
-
Status:
Closed
-
Priority:
Major
-
Resolution: Fixed
-
Affects Version/s: 1.0-RC1
-
Fix Version/s: 1.0.2
-
Component/s: Persistence
-
Labels:None
-
Environment:Windows XP, Grails 1.0RC1_Snapshot, DB2/400 (AS/400 a.k.a. iSeries database)
Description
Most AS/400 legacy database files have composite keys and they rarely have a version number or timestamp. The Grails Hibernate DSL is fantastic but the Composite ID has an issue when creating a new row. The domain.save() operation causes an SQL update. The problem is that the version facility is turned off (via version:false) and the Hibernate generator is set to 'assigned' (id generator:'assigned') and Hibernate is not able to sense that an insert is required. The Hibernate documentation says that it will attempt to SQL-select by the composite id, and determine the update or insert operation required based on whether or not a row is returned with the query. But my log doesn't show the select statement. Only the update, which fails.
What I'd like is to be able to do is explicitly call a save() or update() but Grails domain.save() seems to run Hibernate saveOrUpdate(). Maybe a new method called insert (since save is already used.) Note most of my AS/400 Hibernate applications, as King's Hibernate book suggests on p.325, explicitly calls save() or update(). I always try to get my clients to add a version column and then use triggers to update it but they don't want to bother.
My first workaround for this issue was to put SessionFactory sessionFactory in the controller and call Hibernate's save() directly.
My more recent workaround is to use a custom plug-in that adds a method called insert to all domains, which uses the Hibernate save. Perhaps an optional plug-in is a better solution than adding a method to standard Grails. Note that it's up to the programmer to keep track of new Domain objects and selectively call the new method (I've been putting a transient boolean in my domains.) That said, I'd like to change this to a minor bug.