[vwnc] Fw: Glorp is doing updates instead of doing inserts // was Strange behaviour over index 1

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

[vwnc] Fw: Glorp is doing updates instead of doing inserts // was Strange behaviour over index 1

Maarten Mostert-2
Hi,
 
I encounter some strange behaviour where Glorp actually updates instead of doing inserts. I am still on my export import capabilities of my application. Actually I choose to rebuild my network from. scratch or have the ability to add the contents to an existing one (storing old id's and new ones in a dictionary to do the housekeeping). The enclosed method does this for a simple Hierarchy node of a treeView in my GUI (I marked where things go wrong).  The treeView expect the root to have an id = 1 and the method will not add a node if one with the same name allready exists.
 
readAndRegisterFromStreamOrganisationTreeNode: srs
 
 | aClassAssociation aClassStructure newItem oldID existingNode newRootName |
 aClassAssociation := srs next.
 aClassAssociation value isNil
  ifFalse:
   [importDic add: #OrganisationTreeNode -> Dictionary new.
   aClassAssociation value timesRepeat:
     [aClassStructure := srs next.
     OrganisationTreeNode = aClassStructure key
      ifTrue:
       [newItem := self importReconstructFrom: aClassStructure.
       oldID := newItem id.
       newItem id = 1
        ifTrue:
         [self getGlorpSession inUnitOfWorkDo:
           [existingNode := self getGlorpSession readOneOf: OrganisationTreeNode
              where: [:each | each id = 1].
           existingNode isNil
            ifTrue:
             [self getGlorpSession
              inUnitOfWorkDo: [self getGlorpSession register: newItem]]
            ifFalse:
             [existingNode name = newItem name
              ifFalse:
               [newRootName := Dialog
                  choose: 'Select organisation existingNode name'
                  labels: (Array with: existingNode name with: newItem name)
                  values: (Array with: existingNode name with: newItem name)
                  default: existingNode name.
               existingNode name: newRootName]]]]
        ifFalse:
         [newItem id: nil.
              existingNode := self getGlorpSession readOneOf: OrganisationTreeNode
            where: [:each | each name = newItem name].
               existingNode isNil
          ifTrue:
           [Transcript show:'Justed Counted existing nodes =', (self getGlorpSession count: OrganisationTreeNode) printString;cr.
             self getGlorpSession reset.  "If I reset the session here it provokes the enclosed stack trace, if not it updates newItem with id =1 see Log"
             self getGlorpSession
            inUnitOfWorkDo: [self getGlorpSession register: newItem]]
          ifFalse: [newItem := existingNode]
].
       (importDic at: #OrganisationTreeNode) add: oldID -> Dictionary new.
       ((importDic at: #OrganisationTreeNode) at: oldID) at: #id put: newItem id]]].
 
 
The trancript lgging is as follows from the beginnning of the method:
As you can see it first inserts the root node 'Organisation" then it updates instead of inserting.
 
 

SELECT t1.id, t1.name, t1.shortname
 FROM MMT_ORGANISATION_TREE_NODE t1
 WHERE (t1.id = 1)
(0.015 s)
Begin Transaction
INSERT INTO MMT_ORGANISATION_TREE_NODE (id,name,shortname)  VALUES (1,'Organisation',NULL)
(0.006 s)
Commit Transaction
SELECT t1.id, t1.name, t1.shortname
 FROM MMT_ORGANISATION_TREE_NODE t1
 WHERE (t1.name = 'hjhhhjhjhjhjhj')
(0.013 s)
SELECT  COUNT(*)
 FROM MMT_ORGANISATION_TREE_NODE t1
(0.013 s)Justed Counted existing nodes =1
 
Begin Transaction
select MMT_ORGANISATION_TREE_NODE_id_.nextval from SYS.ALL_OBJECTS  WHERE rownum <= 1
(0.082 s)
UPDATE MMT_ORGANISATION_TREE_NODE SET name = 'hjhhhjhjhjhjhj',shortname = NULL WHERE id = 1
(0.004 s)
Commit Transaction
 

My Descriptor is as follows:
 
 
classModelForOrganisationTreeNode: aClassModel
 aClassModel newAttributeNamed: #id.
 aClassModel newAttributeNamed: #children collectionOf: OrganisationTreeNode.
 aClassModel newAttributeNamed: #parent type: OrganisationTreeNode.
 aClassModel
  newAttributeNamed: #resourcecol
  collection: OrderedCollection
  of: Resource
 
 
descriptorForOrganisationTreeNode: aDescriptor
 | table |
 table := self tableNamed: 'MMT_ORGANISATION_TREE_NODE'.
 aDescriptor table: table.
 (aDescriptor newMapping: DirectMapping) from: #id
  to: (table fieldNamed: 'id').
 (aDescriptor newMapping: DirectMapping) from: #name
  to: (table fieldNamed: 'name').
 (aDescriptor newMapping: DirectMapping) from: #shortname
  to: (table fieldNamed: 'shortname').
 (aDescriptor newMapping: Glorp.OneToOneMapping)
  attributeName: #parent;
  useLinkTable;
  join: (Glorp.Join from: (table fieldNamed: 'id')
     to: ((self tableNamed: 'MMT_ORGANISATION_TREE_LINK') fieldNamed: 'CHILD')).
 (aDescriptor newMapping: Glorp.ToManyMapping)
  attributeName: #children;
  useLinkTable;
  join: (Glorp.Join from: (table fieldNamed: 'id')
     to: ((self tableNamed: 'MMT_ORGANISATION_TREE_LINK') fieldNamed: 'PARENT')).
 (aDescriptor newMapping: Glorp.ToManyMapping)
  attributeName: #resourcecol;
  orderBy: #res_name
 
 
tableForMMT_ORGANISATION_TREE_NODE: aTable
 (aTable createFieldNamed: 'id' type: platform sequence) bePrimaryKey.
 aTable createFieldNamed: 'name' type: (platform varchar: 255).
 aTable createFieldNamed: 'shortname' type: (platform varchar: 60)
 
 

Resetting the glorpSession should not influence the transaction.
It does however with the following stack trace:
 
 
Unhandled exception: 
ORA-00001: violation de contrainte unique (MMT.MMT_ORGANISATION_TREE_NODE_PK)
 
Glorp.GlorpDatabaseWriteError(Glorp.GlorpError)>>signal
Glorp.VWDatabaseAccessor(Glorp.DatabaseAccessor)>>handleError:for:
optimized [] in [] in Glorp.DatabaseAccessor>>executeCommand:returnCursor:
BlockClosure>>cull:
IndexConflict(GenericException)>>performHandler:
IndexConflict(GenericException)>>propagatePrivateFrom:
IndexConflict(GenericException)>>propagateFrom:
IndexConflict(GenericException)>>propagate
IndexConflict(GenericException)>>raiseSignal
IndexConflict class(GenericException class)>>raiseWith:errorString:
OracleThreadedSession(OracleSession)>>resultsExternal
OracleThreadedSession(OracleSession)>>executeExternal
optimized [] in ExternalDatabaseSession>>execute
BlockClosure>>ifCurtailed:
OracleThreadedSession(ExternalDatabaseSession)>>execute
Glorp.VWDatabaseAccessor>>basicExecuteSQLString:returnResult:binding:doing:
Glorp.VWDatabaseAccessor>>basicExecuteSQLStringNoResult:doing:
optimized [] in Glorp.DatabaseAccessor>>executeSQLStringNoResult:doing:forCommand:
Time class>>microsecondsToRun:
Time class>>millisecondsToRun:
Glorp.VWDatabaseAccessor(Glorp.DatabaseAccessor)>>executeSQLStringNoResult:doing:forCommand:
Glorp.InsertCommand(Glorp.RowBasedCommand)>>executeUnboundIn:
optimized [] in [] in Glorp.DatabaseAccessor>>executeCommand:returnCursor:
BlockClosure>>on:do:
optimized [] in Glorp.DatabaseAccessor>>executeCommand:returnCursor:
BlockClosure>>ensure:
Semaphore>>critical:
Glorp.VWDatabaseAccessor(Glorp.DatabaseAccessor)>>executeCommand:returnCursor:
Glorp.VWDatabaseAccessor(Glorp.DatabaseAccessor)>>executeCommand:
Glorp.GlorpSession>>groupWrite:
Glorp.GlorpSession>>writeHomogeneousRows:from:to:
Glorp.GlorpSession>>writeHomogeneousRows:
optimized [] in Glorp.UnitOfWork>>writeRowsForTable:
Dictionary>>do:
Glorp.UnitOfWork>>writeRowsForTable:
optimized [] in Glorp.UnitOfWork>>writeRows
OrderedCollection>>do:
Glorp.UnitOfWork>>writeRows
optimized [] in Glorp.UnitOfWork>>commit
BlockClosure>>ifCurtailed:
Glorp.UnitOfWork>>commit
optimized [] in [] in Glorp.GlorpSession>>commitUnitOfWork
optimized [] in Glorp.DatabaseAccessor>>inTransactionDo:
BlockClosure>>ifCurtailed:
Glorp.VWDatabaseAccessor(Glorp.DatabaseAccessor)>>inTransactionDo:
Glorp.GlorpSession>>inTransactionDo:
optimized [] in Glorp.GlorpSession>>commitUnitOfWork
BlockClosure>>ifCurtailed:
Glorp.GlorpSession>>commitUnitOfWork
optimized [] in Glorp.GlorpSession>>inUnitOfWorkDo:
BlockClosure>>ifCurtailed:
Glorp.GlorpSession>>inUnitOfWorkDo:
MainProject(GlorpFrameWork)>>readAndRegisterFromStreamOrganisationTreeNode:
optimized [] in GlorpFrameWork>>importDatabaseXML
BlockClosure>>ensure:
Cursor>>showWhile:
MainProject(GlorpFrameWork)>>importDatabaseXML

_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: [vwnc] Fw: Glorp is doing updates instead of doing inserts // was Strange behaviour over index 1

Alan Knight-3
This is not trivial to follow, and in particular it's not obvious where newItem comes from. But basically, Glorp's algorithm for whether it's inserting or updating is simple. If it read the object from the database in the first place, then it's an update. Otherwise, it's an insert. And the way it knows if it read it from the database or not is if the cache contains that object. See GlorpSession>>shouldInsert:

It will look up based on the primary key, and decide what to do based on that. So either that primary key corresponds to something you already read from the database, or it's confused about what the primary key fields are. It's probably the first, which is why you get an Oracle error if it tries to insert. You're trying to insert two different rows in the same table with the same primary key. The reason that's different if you reset the session is that if you reset, the cache is now empty, so the cache doesn't contain the object, so it's assumed to be an insert, rather than an update.

At 03:58 PM 2010-01-19, Maarten MOSTERT wrote:
Hi,
 
I encounter some strange behaviour where Glorp actually updates instead of doing inserts. I am still on my export import capabilities of my application. Actually I choose to rebuild my network from. scratch or have the ability to add the contents to an existing one (storing old id's and new ones in a dictionary to do the housekeeping). The enclosed method does this for a simple Hierarchy node of a treeView in my GUI (I marked where things go wrong).  The treeView expect the root to have an id = 1 and the method will not add a node if one with the same name allready exists.
 
readAndRegisterFromStreamOrganisationTreeNode: srs
 
 | aClassAssociation aClassStructure newItem oldID existingNode newRootName |
 aClassAssociation := srs next.
 aClassAssociation value isNil
  ifFalse:
   [importDic add: #OrganisationTreeNode -> Dictionary new.
   aClassAssociation value timesRepeat:
     [aClassStructure := srs next.
     OrganisationTreeNode = aClassStructure key
      ifTrue:
       [newItem := self importReconstructFrom: aClassStructure.
       oldID := newItem id.
       newItem id = 1
        ifTrue:
         [self getGlorpSession inUnitOfWorkDo:
           [existingNode := self getGlorpSession readOneOf: OrganisationTreeNode
              where: [:each | each id = 1].
           existingNode isNil
            ifTrue:
             [self getGlorpSession
              inUnitOfWorkDo: [self getGlorpSession register: newItem]]
            ifFalse:
             [existingNode name = newItem name
              ifFalse:
               [newRootName := Dialog
                  choose: 'Select organisation existingNode name'
                  labels: (Array with: existingNode name with: newItem name)
                  values: (Array with: existingNode name with: newItem name)
                  default: existingNode name.
               existingNode name: newRootName]]]]
        ifFalse:
         [
newItem id: nil.
              existingNode := self getGlorpSession readOneOf: OrganisationTreeNode
            where: [:each | each name = newItem name].
               existingNode isNil
          ifTrue:
           [Transcript show:'Justed Counted existing nodes =', (self getGlorpSession count: OrganisationTreeNode) printString;cr.
             self getGlorpSession reset. 
"If I reset the session here it provokes the enclosed stack trace, if not it updates newItem with id =1 see Log"
             self getGlorpSession
            inUnitOfWorkDo: [self getGlorpSession register: newItem]]
          ifFalse: [newItem := existingNode]
].
       (importDic at: #OrganisationTreeNode) add: oldID -> Dictionary new.
       ((importDic at: #OrganisationTreeNode) at: oldID) at: #id put: newItem id]]].
 
 
The trancript lgging is as follows from the beginnning of the method:
As you can see it first inserts the root node 'Organisation" then it updates instead of inserting.
 
 

SELECT t1.id, t1.name, t1.shortname
 FROM MMT_ORGANISATION_TREE_NODE t1
 WHERE (t1.id = 1)
(0.015 s)
Begin Transaction
INSERT INTO MMT_ORGANISATION_TREE_NODE (id,name,shortname)  VALUES (1,'Organisation',NULL)
(0.006 s)
Commit Transaction
SELECT t1.id, t1.name, t1.shortname
 FROM MMT_ORGANISATION_TREE_NODE t1
 WHERE (t1.name = 'hjhhhjhjhjhjhj')
(0.013 s)
SELECT  COUNT(*)
 FROM MMT_ORGANISATION_TREE_NODE t1
(0.013 s)Justed Counted existing nodes =1
 
Begin Transaction
select MMT_ORGANISATION_TREE_NODE_id_.nextval from SYS.ALL_OBJECTS  WHERE rownum <= 1
(0.082 s)
UPDATE MMT_ORGANISATION_TREE_NODE SET name = 'hjhhhjhjhjhjhj',shortname = NULL WHERE id = 1
(0.004 s)
Commit Transaction
 

My Descriptor is as follows:
 
 
classModelForOrganisationTreeNode: aClassModel
 aClassModel newAttributeNamed: #id.
 aClassModel newAttributeNamed: #children collectionOf: OrganisationTreeNode.
 aClassModel newAttributeNamed: #parent type: OrganisationTreeNode.
 aClassModel
  newAttributeNamed: #resourcecol
  collection: OrderedCollection
  of: Resource
 
 
descriptorForOrganisationTreeNode: aDescriptor
 | table |
 table := self tableNamed: 'MMT_ORGANISATION_TREE_NODE'.
 aDescriptor table: table.
 (aDescriptor newMapping: DirectMapping) from: #id
  to: (table fieldNamed: 'id').
 (aDescriptor newMapping: DirectMapping) from: #name
  to: (table fieldNamed: 'name').
 (aDescriptor newMapping: DirectMapping) from: #shortname
  to: (table fieldNamed: 'shortname').
 (aDescriptor newMapping: Glorp.OneToOneMapping)
  attributeName: #parent;
  useLinkTable;
  join: (Glorp.Join from: (table fieldNamed: 'id')
     to: ((self tableNamed: 'MMT_ORGANISATION_TREE_LINK') fieldNamed: 'CHILD')).
 (aDescriptor newMapping: Glorp.ToManyMapping)
  attributeName: #children;
  useLinkTable;
  join: (Glorp.Join from: (table fieldNamed: 'id')
     to: ((self tableNamed: 'MMT_ORGANISATION_TREE_LINK') fieldNamed: 'PARENT')).
 (aDescriptor newMapping: Glorp.ToManyMapping)
  attributeName: #resourcecol;
  orderBy: #res_name
 
 
tableForMMT_ORGANISATION_TREE_NODE: aTable
 (aTable createFieldNamed: 'id' type: platform sequence) bePrimaryKey.
 aTable createFieldNamed: 'name' type: (platform varchar: 255).
 aTable createFieldNamed: 'shortname' type: (platform varchar: 60)
 
 

Resetting the glorpSession should not influence the transaction.
It does however with the following stack trace:
 
 
Unhandled exception: 
ORA-00001: violation de contrainte unique (MMT.MMT_ORGANISATION_TREE_NODE_PK)
 
Glorp.GlorpDatabaseWriteError(Glorp.GlorpError)>>signal
Glorp.VWDatabaseAccessor(Glorp.DatabaseAccessor)>>handleError:for:
optimized [] in [] in Glorp.DatabaseAccessor>>executeCommand:returnCursor:
BlockClosure>>cull:
IndexConflict(GenericException)>>performHandler:
IndexConflict(GenericException)>>propagatePrivateFrom:
IndexConflict(GenericException)>>propagateFrom:
IndexConflict(GenericException)>>propagate
IndexConflict(GenericException)>>raiseSignal
IndexConflict class(GenericException class)>>raiseWith:errorString:
OracleThreadedSession(OracleSession)>>resultsExternal
OracleThreadedSession(OracleSession)>>executeExternal
optimized [] in ExternalDatabaseSession>>execute
BlockClosure>>ifCurtailed:
OracleThreadedSession(ExternalDatabaseSession)>>execute
Glorp.VWDatabaseAccessor>>basicExecuteSQLString:returnResult:binding:doing:
Glorp.VWDatabaseAccessor>>basicExecuteSQLStringNoResult:doing:
optimized [] in Glorp.DatabaseAccessor>>executeSQLStringNoResult:doing:forCommand:
Time class>>microsecondsToRun:
Time class>>millisecondsToRun:
Glorp.VWDatabaseAccessor(Glorp.DatabaseAccessor)>>executeSQLStringNoResult:doing:forCommand:
Glorp.InsertCommand(Glorp.RowBasedCommand)>>executeUnboundIn:
optimized [] in [] in Glorp.DatabaseAccessor>>executeCommand:returnCursor:
BlockClosure>>on:do:
optimized [] in Glorp.DatabaseAccessor>>executeCommand:returnCursor:
BlockClosure>>ensure:
Semaphore>>critical:
Glorp.VWDatabaseAccessor(Glorp.DatabaseAccessor)>>executeCommand:returnCursor:
Glorp.VWDatabaseAccessor(Glorp.DatabaseAccessor)>>executeCommand:
Glorp.GlorpSession>>groupWrite:
Glorp.GlorpSession>>writeHomogeneousRows:from:to:
Glorp.GlorpSession>>writeHomogeneousRows:
optimized [] in Glorp.UnitOfWork>>writeRowsForTable:
Dictionary>>do:
Glorp.UnitOfWork>>writeRowsForTable:
optimized [] in Glorp.UnitOfWork>>writeRows
OrderedCollection>>do:
Glorp.UnitOfWork>>writeRows
optimized [] in Glorp.UnitOfWork>>commit
BlockClosure>>ifCurtailed:
Glorp.UnitOfWork>>commit
optimized [] in [] in Glorp.GlorpSession>>commitUnitOfWork
optimized [] in Glorp.DatabaseAccessor>>inTransactionDo:
BlockClosure>>ifCurtailed:
Glorp.VWDatabaseAccessor(Glorp.DatabaseAccessor)>>inTransactionDo:
Glorp.GlorpSession>>inTransactionDo:
optimized [] in Glorp.GlorpSession>>commitUnitOfWork
BlockClosure>>ifCurtailed:
Glorp.GlorpSession>>commitUnitOfWork
optimized [] in Glorp.GlorpSession>>inUnitOfWorkDo:
BlockClosure>>ifCurtailed:
Glorp.GlorpSession>>inUnitOfWorkDo:
MainProject(GlorpFrameWork)>>readAndRegisterFromStreamOrganisationTreeNode:
optimized [] in GlorpFrameWork>>importDatabaseXML
BlockClosure>>ensure:
Cursor>>showWhile:
MainProject(GlorpFrameWork)>>importDatabaseXML
_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc

--
Alan Knight [|], Engineering Manager, Cincom Smalltalk

_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc