• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Batch inserts
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Batch inserts


  • Subject: Re: Batch inserts
  • From: Kieran Kelleher <email@hidden>
  • Date: Wed, 19 Dec 2007 14:45:36 -0500

### Eclipse Workspace Patch 1.0
#P ERExtensions
Index: Sources/er/extensions/ERXEOAccessUtilities.java
===================================================================
RCS file: /cvsroot/wonder/Wonder/Common/Frameworks/ERExtensions/Sources/er/extensions/ERXEOAccessUtilities.java,v
retrieving revision 1.94
diff -u -r1.94 ERXEOAccessUtilities.java
--- Sources/er/extensions/ERXEOAccessUtilities.java	2 Dec 2007 16:12:44 -0000	1.94
+++ Sources/er/extensions/ERXEOAccessUtilities.java	19 Dec 2007 19:44:48 -0000
@@ -60,14 +60,14 @@
 public class ERXEOAccessUtilities {
     /** logging support */
     public static final Logger log = Logger.getLogger(ERXEOAccessUtilities.class);
-
+
     /** SQL logger */
     private static Logger sqlLoggingLogger = null;

     /**
      * Finds an entity that is contained in a string. This is used a lot in
      * DirectToWeb. Example: "ListAllStudios"=>Studio
-     *
+     *
      * @param ec
      *            editing context
      * @param string
@@ -105,7 +105,7 @@

     /**
      * Method used to determine if a given entity is a shared entity.
-     *
+     *
      * @param ec
      *            editing context
      * @param entityName
@@ -121,7 +121,7 @@

     /**
      * Convenience method to get the next unique ID from a sequence.
-     *
+     *
      * @param ec
      *            editing context
      * @param modelName
@@ -136,8 +136,8 @@
     // around at
     //		the adaptor level and see if we can't find something better.
     public static Number getNextValFromSequenceNamed(EOEditingContext ec, String modelName, String sequenceName) {
-    	EODatabaseContext dbContext = EOUtilities.databaseContextForModelNamed(ec, modelName);
-    	return ERXSQLHelper.newSQLHelper(dbContext).getNextValFromSequenceNamed(ec, modelName, sequenceName);
+        EODatabaseContext dbContext = EOUtilities.databaseContextForModelNamed(ec, modelName);
+        return ERXSQLHelper.newSQLHelper(dbContext).getNextValFromSequenceNamed(ec, modelName, sequenceName);
     }

     /**
@@ -145,7 +145,7 @@
      * the {@link com.webobjects.eoaccess.EOUtilities EOUtilities}
      * <code>rawRowsForSQL</code> in that it can be used with other statements
      * besides just SELECT without throwing exceptions.
-     *
+     *
      * @param ec
      *            editing context that determines which model group and database
      *            context to use.
@@ -169,7 +169,7 @@
      * the {@link com.webobjects.eoaccess.EOUtilities EOUtilities}
      * <code>rawRowsForSQL</code> in that it can be used with other statements
      * besides just SELECT without throwing exceptions.
-     *
+     *
      * @param ec
      *            editing context that determines which model group and database
      *            context to use.
@@ -193,12 +193,12 @@

     /**
      * Creates the SQL which is used by the provides EOFetchSpecification.
-     *
+     *
      * @param ec
      *            the EOEditingContext
      * @param spec
      *            the EOFetchSpecification in question
-     *
+     *
      * @return the SQL which the EOFetchSpecification would use
      */
     public static String sqlForFetchSpecification(EOEditingContext ec, EOFetchSpecification spec) {
@@ -207,7 +207,7 @@

     /**
      * Returns the raw rows for the given EOSQLExpression.
-     *
+     *
      * @param ec
      *            the EOEditingContext
      * @param spec
@@ -216,7 +216,7 @@
      *            the name of the model in question
      * @param expression
      *            the EOSQLExpression in question
-     *
+     *
      * @return array of dictionaries
      */
     public static NSArray rawRowsForSQLExpression(EOEditingContext ec, String modelName, EOSQLExpression expression) {
@@ -246,7 +246,7 @@
     /**
      * Creates the SQL which is used by the provided EOFetchSpecification,
      * limited by the given range.
-     *
+     *
      * @param ec
      *            the EOEditingContext
      * @param spec
@@ -256,7 +256,7 @@
      * @param end
      *            end of rows to fetch (-1 if not used)
      * @deprecated
-     *
+     *
      * @return the EOSQLExpression which the EOFetchSpecification would use
      */
     public static EOSQLExpression sqlExpressionForFetchSpecification(EOEditingContext ec, EOFetchSpecification spec, long start, long end) {
@@ -269,7 +269,7 @@
     /**
      * Returns the number of rows the supplied EOFetchSpecification would
      * return.
-     *
+     *
      * @param ec
      *            the EOEditingContext
      * @param spec
@@ -278,9 +278,9 @@
      * @deprecated
      */
     public static int rowCountForFetchSpecification(EOEditingContext ec, EOFetchSpecification spec) {
-    	EOEntity entity = ERXEOAccessUtilities.entityNamed(ec, spec.entityName());
-    	EOModel model = entity.model();
-    	return ERXSQLHelper.newSQLHelper(ec, model.name()).rowCountForFetchSpecification(ec, spec);
+        EOEntity entity = ERXEOAccessUtilities.entityNamed(ec, spec.entityName());
+        EOModel model = entity.model();
+        return ERXSQLHelper.newSQLHelper(ec, model.name()).rowCountForFetchSpecification(ec, spec);
     }

     /**
@@ -288,7 +288,7 @@
      * If ec is null, it will try to get at the session via thread storage and
      * use its defaultEditingContext. This is here now so we can remove the
      * delgate in ERXApplication.
-     *
+     *
      * @param ec
      *            editing context used to locate the model group (can be null)
      */
@@ -311,7 +311,7 @@

     /**
      * Similar to the helper in EUUtilities, but allows for null editingContext.
-     *
+     *
      * @param ec
      *            editing context used to locate the model group (can be null)
      * @param entityName
@@ -325,7 +325,7 @@
     /**
      * Creates an aggregate integer attribute for a given function name. These can then
      * be used to query on when using raw rows.
-     *
+     *
      * @param ec
      *            editing context used to locate the model group
      * @param function
@@ -337,13 +337,13 @@
      * @return aggregate function attribute
      */
     public static EOAttribute createAggregateAttribute(EOEditingContext ec, String function, String attributeName, String entityName) {
-    	return ERXEOAccessUtilities.createAggregateAttribute(ec, function, attributeName, entityName, Number.class, "i");
+        return ERXEOAccessUtilities.createAggregateAttribute(ec, function, attributeName, entityName, Number.class, "i");
     }
-
+
     /**
      * Creates an aggregate attribute for a given function name. These can then
      * be used to query on when using raw rows.
-     *
+     *
      * @param ec
      *            editing context used to locate the model group
      * @param function
@@ -353,7 +353,7 @@
      * @param entityName
      *            name of the entity
      * @param valueClass the java class of this attribute's values
-     * @param valueType the EOAttribute value type
+     * @param valueType the EOAttribute value type
      * @return aggregate function attribute
      */
     public static EOAttribute createAggregateAttribute(EOEditingContext ec, String function, String attributeName, String entityName, Class valueClass, String valueType) {
@@ -375,7 +375,7 @@
         aggregate.setColumnName("p_object" + function + "Attribute");
         aggregate.setClassName(valueClass.getName());
         if (valueType != null) {
-        	aggregate.setValueType(valueType);
+            aggregate.setValueType(valueType);
         }
         aggregate.setReadFormat(function + "(t0." + attribute.columnName() + ")");
         return aggregate;
@@ -383,30 +383,30 @@

     /** oracle 9 has a maximum length of 30 characters for table names, column names and constraint names
      * Foreign key constraint names are defined like this from the plugin:<br/><br/>
-     *
+     *
      * TABLENAME_FOEREIGNKEYNAME_FK <br/><br/>
-     *
+     *
      * The whole statement looks like this:<br/><br/>
-     *
+     *
      * ALTER TABLE [TABLENAME] ADD CONSTRAINT [CONSTRAINTNAME] FOREIGN KEY ([FK]) REFERENCES [DESTINATION_TABLE] ([PK]) DEFERRABLE INITIALLY DEFERRED
-     *
+     *
      * THIS means that the tablename and the columnname together cannot
      * be longer than 26 characters.<br/><br/>
-     *
+     *
      * This method checks each foreign key constraint name and if it is longer than 30 characters its replaced
      * with a unique name.
-     *
+     *
      * @see createSchemaSQLForEntitiesInModelWithNameAndOptions
      */
     public static String createSchemaSQLForEntitiesInModelWithNameAndOptionsForOracle9(NSArray entities, String modelName, NSDictionary optionsCreate) {
         EODatabaseContext dc = EOUtilities.databaseContextForModelNamed(ERXEC.newEditingContext(), modelName);
         return ERXSQLHelper.newSQLHelper(dc).createSchemaSQLForEntitiesInModelWithNameAndOptions(entities, modelName, optionsCreate);
     }
-
+
     /**
      * creates SQL to create tables for the specified Entities. This can be used
      * with EOUtilities rawRowsForSQL method to create the tables.
-     *
+     *
      * @param entities
      *            a NSArray containing the entities for which create table
      *            statements should be generated or null if all entitites in the
@@ -428,7 +428,7 @@
      *            <li>EOSchemaGeneration.DropDatabaseKey</li>
      *            <br/><br>
      *            Possible values are <code>YES</code> and <code>NO</code>
-     *
+     *
      * @return a <code>String</code> containing SQL statements to create
      *         tables
      * @deprecated
@@ -437,10 +437,10 @@
         EODatabaseContext dc = EOUtilities.databaseContextForModelNamed(ERXEC.newEditingContext(), modelName);
         return ERXSQLHelper.newSQLHelper(dc).createSchemaSQLForEntitiesInModelWithNameAndOptions(entities, modelName, optionsCreate);
     }
-
+
     /**
      * Creates the schema sql for a set of entities.
-     *
+     *
      * @param entities the entities to create sql for
      * @param databaseContext the database context to use
      * @param optionsCreate the options (@see createSchemaSQLForEntitiesInModelWithNameAndOptions)
@@ -448,13 +448,13 @@
      * @deprecated
      */
     public static String createSchemaSQLForEntitiesWithOptions(NSArray entities, EODatabaseContext databaseContext, NSDictionary optionsCreate) {
-    	return ERXSQLHelper.newSQLHelper(databaseContext).createSchemaSQLForEntitiesWithOptions(entities, databaseContext, optionsCreate);
+        return ERXSQLHelper.newSQLHelper(databaseContext).createSchemaSQLForEntitiesWithOptions(entities, databaseContext, optionsCreate);
     }
-
+
     /**
      * creates SQL to create tables for the specified Entities. This can be used
      * with EOUtilities rawRowsForSQL method to create the tables.
-     *
+     *
      * @param entities
      *            a NSArray containing the entities for which create table
      *            statements should be generated or null if all entitites in the
@@ -474,20 +474,20 @@
      *            </ul>
      *            <br/><br>
      *            Possible values are <code>YES</code> and <code>NO</code>
-     *
+     *
      * @return a <code>String</code> containing SQL statements to create
      *         tables
      * @deprecated
      */
     public static String createSchemaSQLForEntitiesInModelWithName(NSArray entities, String modelName) {
-    	EODatabaseContext databaseContext = EOUtilities.databaseContextForModelNamed(ERXEC.newEditingContext(), modelName);
-    	return ERXSQLHelper.newSQLHelper(databaseContext).createSchemaSQLForEntitiesInModelWithName(entities, modelName);
+        EODatabaseContext databaseContext = EOUtilities.databaseContextForModelNamed(ERXEC.newEditingContext(), modelName);
+        return ERXSQLHelper.newSQLHelper(databaseContext).createSchemaSQLForEntitiesInModelWithName(entities, modelName);
     }

     /**
      * creates SQL to create tables for the specified Entities. This can be used
      * with EOUtilities rawRowsForSQL method to create the tables.
-     *
+     *
      * @param entities
      *            a NSArray containing the entities for which create table
      *            statements should be generated or null if all entitites in the
@@ -502,7 +502,7 @@
      * @deprecated
      */
     public static String createSchemaSQLForEntitiesInDatabaseContext(NSArray entities, EODatabaseContext databaseContext, boolean create, boolean drop) {
-    	return ERXSQLHelper.newSQLHelper(databaseContext).createSchemaSQLForEntitiesInDatabaseContext(entities, databaseContext, create, drop);
+        return ERXSQLHelper.newSQLHelper(databaseContext).createSchemaSQLForEntitiesInDatabaseContext(entities, databaseContext, create, drop);
     }

     /**
@@ -521,7 +521,7 @@
     public static String createIndexSQLForEntities(NSArray entities) {
         return createIndexSQLForEntities(entities, null);
     }
-
+
     /**
      * @deprecated
      */
@@ -554,7 +554,7 @@

     /**
      * Returns true if the exception is an optimistic locking exception.
-     *
+     *
      * @param exception
      *            the exception as recieved from saveChanges()
      * @return true if the error could be handled.
@@ -581,27 +581,27 @@
      */
     //CHECKME ak is this description correct?
     public static NSArray snapshotsForObjectsFromRelationshipNamed(NSArray eos, String relKey) {
-    	NSMutableArray result = new NSMutableArray();
-    	if (eos.count() > 0) {
-    		EOEnterpriseObject eo = (EOEnterpriseObject)eos.lastObject();
-    		String entityName = eo.entityName();
-    		EOEditingContext ec = eo.editingContext();
-    		EOEntity entity = ERXEOAccessUtilities.entityNamed(ec, entityName);
-    		EORelationship relationship = entity.relationshipNamed(relKey);
-    		if(relationship.sourceAttributes().count() == 1) {
-    			EOAttribute attribute = (EOAttribute) relationship.sourceAttributes().lastObject();
-    			EODatabaseContext context = EOUtilities.databaseContextForModelNamed(ec, entity.model().name());
-    			String name = attribute.name();
-    			for (Enumeration e = eos.objectEnumerator(); e.hasMoreElements();) {
-    				EOEnterpriseObject target = (EOEnterpriseObject) e.nextElement();
-    				Object value = (context.snapshotForGlobalID(ec.globalIDForObject(target))).valueForKey(name);
-    				result.addObject(value);
-    			}
-    		} else {
-    			throw new IllegalArgumentException("Has more than one relationship attribute: " + relKey);
-    		}
-    	}
-    	return result;
+        NSMutableArray result = new NSMutableArray();
+        if (eos.count() > 0) {
+            EOEnterpriseObject eo = (EOEnterpriseObject)eos.lastObject();
+            String entityName = eo.entityName();
+            EOEditingContext ec = eo.editingContext();
+            EOEntity entity = ERXEOAccessUtilities.entityNamed(ec, entityName);
+            EORelationship relationship = entity.relationshipNamed(relKey);
+            if(relationship.sourceAttributes().count() == 1) {
+                EOAttribute attribute = (EOAttribute) relationship.sourceAttributes().lastObject();
+                EODatabaseContext context = EOUtilities.databaseContextForModelNamed(ec, entity.model().name());
+                String name = attribute.name();
+                for (Enumeration e = eos.objectEnumerator(); e.hasMoreElements();) {
+                    EOEnterpriseObject target = (EOEnterpriseObject) e.nextElement();
+                    Object value = (context.snapshotForGlobalID(ec.globalIDForObject(target))).valueForKey(name);
+                    result.addObject(value);
+                }
+            } else {
+                throw new IllegalArgumentException("Has more than one relationship attribute: " + relKey);
+            }
+        }
+        return result;
     }

     /**
@@ -611,7 +611,7 @@
      * the same method that EOF uses by default for generating primary keys. See
      * {@link ERXGeneratesPrimaryKeyInterface}for more information about using
      * a newly created dictionary as the primary key for an enterprise object.
-     *
+     *
      * @param ec
      *            editing context
      * @param entityName
@@ -619,32 +619,32 @@
      * @return a dictionary containing a new primary key for the given entity.
      */
     public static NSDictionary primaryKeyDictionaryForEntity(EOEditingContext ec, String entityName) {
-    	EOEntity entity = ERXEOAccessUtilities.entityNamed(ec, entityName);
-    	EODatabaseContext dbContext = EODatabaseContext.registeredDatabaseContextForModel(entity.model(), ec);
-    	NSDictionary primaryKey = null;
-    	dbContext.lock();
-    	try {
-    		EOAdaptorChannel adaptorChannel = dbContext.availableChannel().adaptorChannel();
-    		if (!adaptorChannel.isOpen()) {
-    			adaptorChannel.openChannel();
-    		}
-    		NSArray arr = adaptorChannel.primaryKeysForNewRowsWithEntity(1, entity);
-    		if (arr != null) {
-    			primaryKey = (NSDictionary) arr.lastObject();
-    		} else {
-    			log.warn("Could not get primary key for entity: " + entityName + " exception");
-    		}
-    	} catch (Exception e) {
-    		log.error("Caught exception when generating primary key for entity: " + entityName + " exception: " + e, e);
-    	} finally {
-    		dbContext.unlock();
-    	}
-    	return primaryKey;
+        EOEntity entity = ERXEOAccessUtilities.entityNamed(ec, entityName);
+        EODatabaseContext dbContext = EODatabaseContext.registeredDatabaseContextForModel(entity.model(), ec);
+        NSDictionary primaryKey = null;
+        dbContext.lock();
+        try {
+            EOAdaptorChannel adaptorChannel = dbContext.availableChannel().adaptorChannel();
+            if (!adaptorChannel.isOpen()) {
+                adaptorChannel.openChannel();
+            }
+            NSArray arr = adaptorChannel.primaryKeysForNewRowsWithEntity(1, entity);
+            if (arr != null) {
+                primaryKey = (NSDictionary) arr.lastObject();
+            } else {
+                log.warn("Could not get primary key for entity: " + entityName + " exception");
+            }
+        } catch (Exception e) {
+            log.error("Caught exception when generating primary key for entity: " + entityName + " exception: " + e, e);
+        } finally {
+            dbContext.unlock();
+        }
+        return primaryKey;
     }
-
+
     /**
      * Creates an array containing all of the primary keys of the given objects.
-     *
+     *
      * @param eos
      *            array of enterprise objects
      */
@@ -672,7 +672,7 @@
     /**
      * Creates an array of relationships and attributes from the given keypath to give to the
      * EOSQLExpression method <code>sqlStringForAttributePath</code>. If the last element is a
-     * relationship, then the relationship's source attribute will get chosen. As such, this can only
+     * relationship, then the relationship's source attribute will get chosen. As such, this can only
      * work for single-value relationships in the last element.
      * @param entity
      * @param keyPath
@@ -686,9 +686,9 @@
             part = parts[i];
             EORelationship relationship = entity.anyRelationshipNamed(part);
             if(relationship == null) {
-            	// CHECKME AK:  it would probably be better to return null
-            	// to indocate that this is not a valid path?
-            	return NSArray.EmptyArray;
+                // CHECKME AK:  it would probably be better to return null
+                // to indocate that this is not a valid path?
+                return NSArray.EmptyArray;
             }
             entity = relationship.destinationEntity();
             result.addObject(relationship);
@@ -701,9 +701,9 @@
                 throw new IllegalArgumentException("Last element is not an attribute nor a relationship: " + keyPath);
             }
             if (relationship.isFlattened()) {
-            	NSArray path = attributePathForKeyPath(entity, relationship.definition());
-            	result.addObjectsFromArray(path);
-            	return result;
+                NSArray path = attributePathForKeyPath(entity, relationship.definition());
+                result.addObjectsFromArray(path);
+                return result;
             } else {
                 attribute = ((EOJoin) relationship.joins().lastObject()).sourceAttribute();
             }
@@ -717,12 +717,12 @@
      * @deprecated
      */
     public static String sqlWhereClauseStringForKey(EOSQLExpression e, String key, NSArray valueArray) {
-    	return ERXSQLHelper.newSQLHelper(e).sqlWhereClauseStringForKey(e, key, valueArray);
+        return ERXSQLHelper.newSQLHelper(e).sqlWhereClauseStringForKey(e, key, valueArray);
     }

     /**
      * Returns the database context for an EO.
-     *
+     *
      * @param eo the EO to get a database context for
      * @return the eo's database context
      */
@@ -732,11 +732,11 @@
         EODatabaseContext databaseContext = (EODatabaseContext) osc.objectStoreForObject(eo);
         return databaseContext;
     }
-
+
     /**
      * Returns the database context for the given entity in the given
      * EOObjectStoreCoordinator
-     *
+     *
      * @param entityName
      * @param osc
      * @return
@@ -750,7 +750,7 @@
     /**
      * Closes the (JDBC) Connection from all database channels for the specified
      * EOObjectStoreCoordinator
-     *
+     *
      * @param osc,
      *            the EOObjectStoreCoordinator from which the (JDBC)Connections
      *            should be closed
@@ -769,7 +769,7 @@
                     EODatabaseChannel dbch = (EODatabaseChannel) channels.objectAtIndex(j);
                     if (!dbch.adaptorChannel().adaptorContext().hasOpenTransaction()) {
                         dbch.adaptorChannel().closeChannel();
-
+
                     } else {
                         log.warn("could not close Connection from " + dbch + " because its EOAdaptorContext "
                                 + dbch.adaptorChannel().adaptorContext() + " had open Transactions");
@@ -791,7 +791,7 @@
      * @return
      */
     private static Set _keysWithWarning = Collections.synchronizedSet(new HashSet());
-
+
     public static EOEntity destinationEntityForKeyPath(EOEntity entity, String keyPath) {
         if(keyPath == null || keyPath.length() == 0) {
             return entity;
@@ -802,12 +802,12 @@
             EORelationship rel = entity.anyRelationshipNamed(key);
             if(rel == null) {
                 if(entity.anyAttributeNamed(key) == null) {
-                	if(key.indexOf("@") != 0) {
-                		if(!_keysWithWarning.contains(key + "-" + entity)) {
-                			_keysWithWarning.add(key + "-" + entity);
-                			log.warn("No relationship or attribute <" + key + "> in entity: " + entity);
-                		}
-                	}
+                    if(key.indexOf("@") != 0) {
+                        if(!_keysWithWarning.contains(key + "-" + entity)) {
+                            _keysWithWarning.add(key + "-" + entity);
+                            log.warn("No relationship or attribute <" + key + "> in entity: " + entity);
+                        }
+                    }
                 }
                 return null;
             }
@@ -817,13 +817,13 @@
     }

     /** Returns the EOEntity for the provided EOEnterpriseObject if one exists
-     *
+     *
      * @param eo the EOEnterpriseObject
      * @return the EOEntity from the EOEnterpriseObject
      */
     public static EOEntity entityForEo(EOEnterpriseObject eo) {
         EOClassDescription classDesc = eo.classDescription();
-
+
         if (classDesc instanceof EOEntityClassDescription)
             return ((EOEntityClassDescription)classDesc).entity();
         return null;
@@ -838,18 +838,18 @@
         NSArray cpNames = entity.classPropertyNames();

         if (includeAttributes) {
-	        for (int i = attributes.count(); i-- > 0;) {
-	            EOAttribute att = (EOAttribute) attributes.objectAtIndex(i);
-	            String name = att.name();
-	            if (cpNames.containsObject(name) && !parentAttributeNames.containsObject(name)) {
-	                ret.addObject(att);
-	            }
-	        }
+            for (int i = attributes.count(); i-- > 0;) {
+                EOAttribute att = (EOAttribute) attributes.objectAtIndex(i);
+                String name = att.name();
+                if (cpNames.containsObject(name) && !parentAttributeNames.containsObject(name)) {
+                    ret.addObject(att);
+                }
+            }
         }
-
+
         NSArray parentRelationships = (NSArray) entity.parentEntity().relationships().valueForKey("name");
         NSArray relationships = entity.relationships();
-
+
         for (int i = relationships.count(); i-- > 0;) {
             EORelationship element = (EORelationship) relationships.objectAtIndex(i);
             if ((element.isToMany() && includeToManyRelationships)
@@ -864,7 +864,7 @@
     }

     public static NSArray externalNamesForEntity(EOEntity entity, boolean includeParentEntities) {
-        if (includeParentEntities) {
+        if (includeParentEntities) {
             entity = rootEntityForEntity(entity);
         }
         NSMutableArray entityNames = new NSMutableArray();
@@ -875,7 +875,7 @@
                 entityNames.addObjectsFromArray(names);
             }
         }
-        entityNames.addObject(entity.externalName());
+        entityNames.addObject(entity.externalName());
         return ERXArrayUtilities.arrayWithoutDuplicates(entityNames);
     }

@@ -928,96 +928,96 @@
                 }
             }
             if (ERXStats.isTrackingStatistics()) {
-            	String statement = expression.statement();
-            	// AK: special postgres data PK handling
-            	statement = statement.replaceAll("decode\\(.*?\\)", "?");
-            	// IN's can be quite long and are normally not bound
-               	statement = statement.replaceAll(" IN \\(.*?\\)", " IN ([removed])");
-               	statement = statement.replaceAll("([a-zA-Z0-9_\\.]+)\\s+IN \\(.*?\\)(\\s+OR\\s+\\1\\s+IN \\(.*?\\))+", " IN ([multi removed])");
-               	// the cols are always the same, replace with *
-               	statement = statement.replaceAll("((t0|T0)\\.[a-zA-Z0-9_]+\\,\\s*)*(t0|T0)\\.[a-zA-Z0-9_\\.]+\\s+FROM\\s+", "t0.* FROM ");
-            	ERXStats.addDurationForKey(millisecondsNeeded, entityName + ": " +statement);
+                String statement = expression.statement();
+                // AK: special postgres data PK handling
+                statement = statement.replaceAll("decode\\(.*?\\)", "?");
+                // IN's can be quite long and are normally not bound
+                   statement = statement.replaceAll(" IN \\(.*?\\)", " IN ([removed])");
+                   statement = statement.replaceAll("([a-zA-Z0-9_\\.]+)\\s+IN \\(.*?\\)(\\s+OR\\s+\\1\\s+IN \\(.*?\\))+", " IN ([multi removed])");
+                   // the cols are always the same, replace with *
+                   statement = statement.replaceAll("((t0|T0)\\.[a-zA-Z0-9_]+\\,\\s*)*(t0|T0)\\.[a-zA-Z0-9_\\.]+\\s+FROM\\s+", "t0.* FROM ");
+                ERXStats.addDurationForKey(millisecondsNeeded, entityName + ": " +statement);
             }
             if (needsLog) {
                 String logString = createLogString(channel, expression, millisecondsNeeded);
-        		if (logString.length() > maxLength) {
-        		    logString = logString.substring(0, maxLength);
-        		}
+                if (logString.length() > maxLength) {
+                    logString = logString.substring(0, maxLength);
+                }

                 if (millisecondsNeeded > errorMilliseconds) {
-        		    sqlLoggingLogger.error(logString, new RuntimeException("Statement running too long"));
-        		} else if (millisecondsNeeded > warnMilliseconds) {
-        		    sqlLoggingLogger.warn(logString);
-        		} else if (millisecondsNeeded > infoMilliseconds) {
-        		    if (sqlLoggingLogger.isInfoEnabled()) {
-        		        sqlLoggingLogger.info(logString);
-        		    }
-        		} else if (millisecondsNeeded > debugMilliseconds) {
-        		    if (sqlLoggingLogger.isDebugEnabled()) {
-        		        sqlLoggingLogger.debug(logString);
-        		    }
-        		}
+                    sqlLoggingLogger.error(logString, new RuntimeException("Statement running too long"));
+                } else if (millisecondsNeeded > warnMilliseconds) {
+                    sqlLoggingLogger.warn(logString);
+                } else if (millisecondsNeeded > infoMilliseconds) {
+                    if (sqlLoggingLogger.isInfoEnabled()) {
+                        sqlLoggingLogger.info(logString);
+                    }
+                } else if (millisecondsNeeded > debugMilliseconds) {
+                    if (sqlLoggingLogger.isDebugEnabled()) {
+                        sqlLoggingLogger.debug(logString);
+                    }
+                }

             }
         }
     }

-	public static String createLogString(EOAdaptorChannel channel, EOSQLExpression expression, long millisecondsNeeded) {
+    public static String createLogString(EOAdaptorChannel channel, EOSQLExpression expression, long millisecondsNeeded) {
         String entityName = (expression.entity() != null ? expression.entity().name() : "Unknown");
-		String description = "\"" + entityName + "\"@" + channel.adaptorContext().hashCode() + " expression took "
-		        + millisecondsNeeded + " ms: " + expression.statement();
-		StringBuffer sb = new StringBuffer();
-		NSArray variables = expression.bindVariableDictionaries();
-		int cnt = variables != null ? variables.count() : 0;
-		if (cnt > 0) {
-		    sb.append(" withBindings: ");
-		    for (int i = 0; i < cnt; i++) {
-		        NSDictionary nsdictionary = (NSDictionary) variables.objectAtIndex(i);
-		        Object obj = nsdictionary.valueForKey("BindVariableValue");
-		        String attributeName = (String) nsdictionary.valueForKey("BindVariableName");
-		        if (obj instanceof String) {
-		            obj = EOSQLExpression.sqlStringForString((String) obj);
-		        } else if (obj instanceof NSData) {
-		            // ak: this is just for logging, however we would
-		            // like to get readable data
-		            // in particular for PKs and with postgres this
-		            // works.
-		            // plain EOF is broken, though
-		            try {
-		                if (((NSData) obj).length() < 50) {
-		                    obj = expression.sqlStringForData((NSData) obj);
-		                }
-		            } catch (ArrayIndexOutOfBoundsException ex) {
-		                // ignore, this is a bug in EOF
-		            }
-		            if (obj instanceof NSData) {
-		                // produces very yucky output
-		                obj = obj.toString();
-		            }
-		        } else {
-		            if (expression.entity() != null) {
-		                EOAttribute attribute = expression.entity().anyAttributeNamed(attributeName);
-		                if (attribute != null) {
-		                    obj = expression.formatValueForAttribute(obj, attribute);
-		                }
-		            }
-		        }
-		        if (i != 0)
-		            sb.append(", ");
-		        sb.append(i + 1);
-		        sb.append(":");
-		        sb.append(obj);
-		        sb.append("[");
-		        sb.append(attributeName);
-		        sb.append("]");
-		    }
-		}
-		description = description + sb.toString();
-
-		return description;
-	}
-
-
+        String description = "\"" + entityName + "\"@" + channel.adaptorContext().hashCode() + " expression took "
+                + millisecondsNeeded + " ms: " + expression.statement();
+        StringBuffer sb = new StringBuffer();
+        NSArray variables = expression.bindVariableDictionaries();
+        int cnt = variables != null ? variables.count() : 0;
+        if (cnt > 0) {
+            sb.append(" withBindings: ");
+            for (int i = 0; i < cnt; i++) {
+                NSDictionary nsdictionary = (NSDictionary) variables.objectAtIndex(i);
+                Object obj = nsdictionary.valueForKey("BindVariableValue");
+                String attributeName = (String) nsdictionary.valueForKey("BindVariableName");
+                if (obj instanceof String) {
+                    obj = EOSQLExpression.sqlStringForString((String) obj);
+                } else if (obj instanceof NSData) {
+                    // ak: this is just for logging, however we would
+                    // like to get readable data
+                    // in particular for PKs and with postgres this
+                    // works.
+                    // plain EOF is broken, though
+                    try {
+                        if (((NSData) obj).length() < 50) {
+                            obj = expression.sqlStringForData((NSData) obj);
+                        }
+                    } catch (ArrayIndexOutOfBoundsException ex) {
+                        // ignore, this is a bug in EOF
+                    }
+                    if (obj instanceof NSData) {
+                        // produces very yucky output
+                        obj = obj.toString();
+                    }
+                } else {
+                    if (expression.entity() != null) {
+                        EOAttribute attribute = expression.entity().anyAttributeNamed(attributeName);
+                        if (attribute != null) {
+                            obj = expression.formatValueForAttribute(obj, attribute);
+                        }
+                    }
+                }
+                if (i != 0)
+                    sb.append(", ");
+                sb.append(i + 1);
+                sb.append(":");
+                sb.append(obj);
+                sb.append("[");
+                sb.append(attributeName);
+                sb.append("]");
+            }
+        }
+        description = description + sb.toString();
+
+        return description;
+    }
+
+
     /**
      * Creates an AND qualifier of EOKeyValueQualifiers for every keypath in the given array of attributes.
      * @param keys
@@ -1042,7 +1042,7 @@

     /**
      * Filters a list of relationships for only the ones that
-     * have a given EOAttribute as a source attribute.
+     * have a given EOAttribute as a source attribute.
      * @param attrib EOAttribute to filter source attributes of
      *      relationships.
      * @param rels array of EORelationship objects.
@@ -1111,7 +1111,7 @@
         EOEditingContext ec = eo.editingContext();
         NSArray keys = changedValues.allKeys();
         NSMutableSet relationships = new NSMutableSet();
-
+
         for (int i=0; i<keys.count(); i++) {
             String key = (String)keys.objectAtIndex(i);
             EOAttribute attrib = entity.attributeNamed(key);
@@ -1147,10 +1147,10 @@
             }
         }
     }
-
+
     /**
      * Deals with the nitty-gritty of direct row manipulation by
-     * correctly opening, closing, locking and unlocking the
+     * correctly opening, closing, locking and unlocking the
      * needed EOF objects for direct row manipulation. Wraps the
      * actions in a transaction.
      * The API is not really finalized, if someone has a better idea
@@ -1158,7 +1158,7 @@
      * @author ak
      */
     public static abstract class ChannelAction {
-
+
         protected abstract int doPerform(EOAdaptorChannel channel);

         public int perform(EOEditingContext ec, String modelName) {
@@ -1182,7 +1182,7 @@
                     } catch(RuntimeException ex) {
                         channel.adaptorContext().rollbackTransaction();
                         throw ex;
-                    }
+                    }
                 } finally {
                     if(!wasOpen) {
                         channel.closeChannel();
@@ -1197,15 +1197,15 @@
     }

     /**
-     * Deletes rows described by the qualifier. Note that the values and the qualifier need to be on an attribute
-     * and not on a relationship level. I.e. you need to give relationshipForeignKey = pk of object instead of
+     * Deletes rows described by the qualifier. Note that the values and the qualifier need to be on an attribute
+     * and not on a relationship level. I.e. you need to give relationshipForeignKey = pk of object instead of
      * relatedObject = object
      * @param ec
      * @param entityName
      * @param qualifier
      * @return
      */
-    public static int deleteRowsDescribedByQualifier(EOEditingContext ec, String entityName,
+    public static int deleteRowsDescribedByQualifier(EOEditingContext ec, String entityName,
             final EOQualifier qualifier) {
         final EOEntity entity = entityNamed(ec, entityName);
         ChannelAction action = new ChannelAction() {
@@ -1217,8 +1217,8 @@
     }

     /**
-     * Updates rows described by the qualifier. Note that the values and the qualifier need to be on an attribute
-     * and not on a relationship level. I.e. you need to give relationshipForeignKey = pk of object instead of
+     * Updates rows described by the qualifier. Note that the values and the qualifier need to be on an attribute
+     * and not on a relationship level. I.e. you need to give relationshipForeignKey = pk of object instead of
      * relatedObject = object. The newValues dictionaries also holds foreign keys, not objects.
      * @param ec
      * @param entityName
@@ -1226,7 +1226,7 @@
      * @param newValues
      * @return
      */
-    public static int updateRowsDescribedByQualifier(EOEditingContext ec, String entityName,
+    public static int updateRowsDescribedByQualifier(EOEditingContext ec, String entityName,
             final EOQualifier qualifier, final NSDictionary newValues) {
         final EOEntity entity = entityNamed(ec, entityName);
         ChannelAction action = new ChannelAction() {
@@ -1236,7 +1236,7 @@
         };
         return action.perform(ec, entity.model().name());
     }
-
+
     /**
      * Tries to get the plugin name for a JDBC based model.
      * @param model
@@ -1251,43 +1251,43 @@
         if ("JDBC".equals(model.adaptorName())) {
             NSDictionary connectionDictionary = model.connectionDictionary();
             if (connectionDictionary != null) {
-            	pluginName = guessPluginNameForConnectionDictionary(connectionDictionary);
+                pluginName = guessPluginNameForConnectionDictionary(connectionDictionary);
             }
         }
         return pluginName;
     }
-
+
     /**
      * Tries to get the plugin name for a connection dictionary.
      * @param connectionDictionary the connectionDictionary to guess a plugin name for
      * @return the plugin name
      */
     public static String guessPluginNameForConnectionDictionary(NSDictionary connectionDictionary) {
-    	String pluginName = null;
-	    String jdbcUrl = (String) connectionDictionary.objectForKey("URL");
-	    if (jdbcUrl != null) {
-	        pluginName = (String) connectionDictionary.objectForKey("plugin");
-	        if (pluginName == null || pluginName.trim().length() == 0) {
-	            pluginName = JDBCPlugIn.plugInNameForURL(jdbcUrl);
-	            if (pluginName == null) {
-	            	// AK: this is a hack that is totally bogus....
-	                int firstColon = jdbcUrl.indexOf(':');
-	                int secondColon = jdbcUrl.indexOf(':', firstColon + 1);
-	                if (firstColon != -1 && secondColon != -1) {
-	                    pluginName = jdbcUrl.substring(firstColon + 1, secondColon);
-	                }
-	            } else {
-	                pluginName = ERXStringUtilities.lastPropertyKeyInKeyPath(pluginName);
-	                pluginName = pluginName.replaceFirst("PlugIn", "");
-	            }
-	        }
-	    }
+        String pluginName = null;
+        String jdbcUrl = (String) connectionDictionary.objectForKey("URL");
+        if (jdbcUrl != null) {
+            pluginName = (String) connectionDictionary.objectForKey("plugin");
+            if (pluginName == null || pluginName.trim().length() == 0) {
+                pluginName = JDBCPlugIn.plugInNameForURL(jdbcUrl);
+                if (pluginName == null) {
+                    // AK: this is a hack that is totally bogus....
+                    int firstColon = jdbcUrl.indexOf(':');
+                    int secondColon = jdbcUrl.indexOf(':', firstColon + 1);
+                    if (firstColon != -1 && secondColon != -1) {
+                        pluginName = jdbcUrl.substring(firstColon + 1, secondColon);
+                    }
+                } else {
+                    pluginName = ERXStringUtilities.lastPropertyKeyInKeyPath(pluginName);
+                    pluginName = pluginName.replaceFirst("PlugIn", "");
+                }
+            }
+        }
         if (pluginName != null && pluginName.trim().length() == 0) {
           pluginName = null;
         }
         return pluginName;
     }
-
+
      /**
       * Returns a new fetch spec by morphing sort oderings containing the keys <code>foo.name</code>
       * returning <code>foo.name_de</code> where appropriate.
@@ -1304,7 +1304,7 @@
                  String key = item.key();
                  NSArray path = NSArray.componentsSeparatedByString(key, ".");
                  if(path.count() > 1) {
-                	 String prefix = "";
+                     String prefix = "";
                      String attributeName = (String) path.lastObject();
                      EOEntity entity = ERXEOAccessUtilities.entityNamed(ec, fetchSpecification.entityName());
                      for (int i = 0; i < path.count() - 1; i++) {
@@ -1314,12 +1314,12 @@
                          prefix += part + ".";
                      }
                      if(entity.attributeNamed(attributeName) == null) {
-                    	 EOClassDescription cd = entity.classDescriptionForInstances();
+                         EOClassDescription cd = entity.classDescriptionForInstances();
                          if(cd instanceof ERXEntityClassDescription) {
-                        	 String localizedKey = ((ERXEntityClassDescription)cd).localizedKey(attributeName);
-                        	 if(localizedKey != null) {
+                             String localizedKey = ((ERXEntityClassDescription)cd).localizedKey(attributeName);
+                             if(localizedKey != null) {
                                  item = new EOSortOrdering(prefix + localizedKey, item.selector());
-                        	 }
+                             }
                          }
                      }
                  }
@@ -1329,10 +1329,10 @@
          }
          return fetchSpecification;
      }
-
+
      /**
       * Batch fetch a relationship, optionally skipping any relationship that has already faulted in its to-many relationship.
-      *
+      *
       * @param databaseContext the database context to fetch in
       * @param entityName the name of the entity to fetch on
       * @param relationshipName the name of the relationship in that entity to fetch
@@ -1341,14 +1341,14 @@
       * @param skipFaultedRelationships if true, skip any object whose relationship has already been faulted
       */
      public static void batchFetchRelationship(EODatabaseContext databaseContext, String entityName, String relationshipName, NSArray objects, EOEditingContext editingContext, boolean skipFaultedRelationships) {
-    	 EOEntity entity = EOModelGroup.defaultGroup().entityNamed(entityName);
-    	 EORelationship relationship = entity.relationshipNamed(relationshipName);
-    	 ERXEOAccessUtilities.batchFetchRelationship(databaseContext, relationship, objects, editingContext, skipFaultedRelationships);
+         EOEntity entity = EOModelGroup.defaultGroup().entityNamed(entityName);
+         EORelationship relationship = entity.relationshipNamed(relationshipName);
+         ERXEOAccessUtilities.batchFetchRelationship(databaseContext, relationship, objects, editingContext, skipFaultedRelationships);
      }
-
+
      /**
       * Batch fetch a relationship, optionally skipping any relationship that has already faulted in its to-many relationship.
-      *
+      *
       * @param databaseContext the database context to fetch in
       * @param relationship the relationship to fetch
       * @param objects the objects to fetch the relationship on
@@ -1356,150 +1356,248 @@
       * @param skipFaultedRelationships if true, skip any object whose relationship has already been faulted
       */
      public static void batchFetchRelationship(EODatabaseContext databaseContext, EORelationship relationship, NSArray objects, EOEditingContext editingContext, boolean skipFaultedRelationships) {
-    	 NSArray objectsToBatchFetch;
-    	 if (skipFaultedRelationships && relationship.isToMany()) {
-	         NSMutableArray objectsWithUnfaultedRelationships = new NSMutableArray();
-	         String relationshipName = relationship.name();
-	         Enumeration objectsEnum = objects.objectEnumerator();
-	         while (objectsEnum.hasMoreElements()) {
-	         	EOEnterpriseObject object = (EOEnterpriseObject)objectsEnum.nextElement();
-	         	Object relationshipValue = object.storedValueForKey(relationshipName);
-	         	if (EOFaultHandler.isFault(relationshipValue)) {
-	         		objectsWithUnfaultedRelationships.addObject(object);
-	         	}
-	         }
-	         objectsToBatchFetch = objectsWithUnfaultedRelationships;
-    	 }
-    	 else {
-    		 objectsToBatchFetch = objects;
-    	 }
-    	 if (objects.count() > 0) {
-			 databaseContext.batchFetchRelationship(relationship, objectsToBatchFetch, editingContext);
-    	 }
+         NSArray objectsToBatchFetch;
+         if (skipFaultedRelationships && relationship.isToMany()) {
+             NSMutableArray objectsWithUnfaultedRelationships = new NSMutableArray();
+             String relationshipName = relationship.name();
+             Enumeration objectsEnum = objects.objectEnumerator();
+             while (objectsEnum.hasMoreElements()) {
+                 EOEnterpriseObject object = (EOEnterpriseObject)objectsEnum.nextElement();
+                 Object relationshipValue = object.storedValueForKey(relationshipName);
+                 if (EOFaultHandler.isFault(relationshipValue)) {
+                     objectsWithUnfaultedRelationships.addObject(object);
+                 }
+             }
+             objectsToBatchFetch = objectsWithUnfaultedRelationships;
+         }
+         else {
+             objectsToBatchFetch = objects;
+         }
+         if (objects.count() > 0) {
+             databaseContext.batchFetchRelationship(relationship, objectsToBatchFetch, editingContext);
+         }
+     }
+
+     /**
+      * In a multi-OSC or multi-instance scenario, when there are bugs, it is possible for the snapshots to become out of
+      * sync with the database. It is useful to have some way to determine when exactly this condition occurs for writing
+      * test cases.
+      *
+      * @return a set of strings that describe the mismatches that occurred
+      */
+     public static NSSet verifyAllSnapshots() {
+         NSMutableSet mismatches = new NSMutableSet();
+         NSMutableSet verifiedDatabases = new NSMutableSet();
+         EOEditingContext editingContext = ERXEC.newEditingContext();
+         EOModelGroup modelGroup = EOModelGroup.defaultGroup();
+         Enumeration modelsEnum = modelGroup.models().objectEnumerator();
+         while (modelsEnum.hasMoreElements()) {
+             EOModel model = (EOModel) modelsEnum.nextElement();
+             EODatabaseContext databaseContext = null;
+             try {
+                 databaseContext = EODatabaseContext.registeredDatabaseContextForModel(model, editingContext);
+             }
+             catch (IllegalStateException e) {
+                 log.warn("Model " + model.name() + " failed: " + e.getMessage());
+             }
+             if (databaseContext != null) {
+                 databaseContext.lock();
+                 try {
+                     EODatabase database = databaseContext.database();
+                     if (!verifiedDatabases.containsObject(database)) {
+                         Enumeration gidEnum = database.snapshots().keyEnumerator();
+                         while (gidEnum.hasMoreElements()) {
+                             EOGlobalID gid = (EOGlobalID) gidEnum.nextElement();
+                             if (gid instanceof EOKeyGlobalID) {
+                                 EOEnterpriseObject eo = null;
+                                 EOKeyGlobalID keyGID = (EOKeyGlobalID) gid;
+                                 String entityName = keyGID.entityName();
+                                 EOEntity entity = modelGroup.entityNamed(entityName);
+                                 NSDictionary snapshot = database.snapshotForGlobalID(gid);
+                                 if (snapshot != null) {
+                                     EOQualifier gidQualifier = entity.qualifierForPrimaryKey(entity.primaryKeyForGlobalID(gid));
+                                     EOFetchSpecification gidFetchSpec = new EOFetchSpecification(entityName, gidQualifier, null);
+
+                                     NSMutableDictionary databaseSnapshotClone;
+                                     NSMutableDictionary memorySnapshotClone = snapshot.mutableClone();
+                                     EOAdaptorContext context;
+                                     EOAdaptorChannel channel = databaseContext.availableChannel().adaptorChannel();
+                                     channel.openChannel();
+                                     channel.selectAttributes(entity.attributesToFetch(), gidFetchSpec, false, entity);
+                                     NSDictionary nextRow;
+                                     try {
+                                         databaseSnapshotClone = channel.fetchRow().mutableClone();
+                                     }
+                                     finally {
+                                         channel.cancelFetch();
+                                     }
+                                     // gidFetchSpec.setRefreshesRefetchedObjects(true);
+                                     // NSArray databaseEOs = editingContext.objectsWithFetchSpecification(gidFetchSpec);
+                                     if (databaseSnapshotClone == null) {
+                                         mismatches.addObject(gid + " was deleted in the database, but the snapshot still exists: " + memorySnapshotClone);
+                                     }
+                                     else {
+                                         // NSMutableDictionary refreshedSnapshotClone =
+                                         // database.snapshotForGlobalID(gid).mutableClone();
+                                         ERXDictionaryUtilities.removeMatchingEntries(memorySnapshotClone, databaseSnapshotClone);
+                                         if (databaseSnapshotClone.count() > 0 || memorySnapshotClone.count() > 0) {
+                                             mismatches.addObject(gid + " doesn't match the database: original = " + memorySnapshotClone + "; database = " + databaseSnapshotClone);
+                                         }
+                                         eo = (EOEnterpriseObject) editingContext.objectsWithFetchSpecification(gidFetchSpec).objectAtIndex(0);
+                                     }
+                                 }
+
+                                 if (eo != null) {
+                                     Enumeration relationshipsEnum = entity.relationships().objectEnumerator();
+                                     while (relationshipsEnum.hasMoreElements()) {
+                                         EORelationship relationship = (EORelationship) relationshipsEnum.nextElement();
+                                         String relationshipName = relationship.name();
+                                         NSArray originalDestinationGIDs = database.snapshotForSourceGlobalID(keyGID, relationshipName);
+                                         if (originalDestinationGIDs != null) {
+                                             NSMutableArray newDestinationGIDs = new NSMutableArray();
+                                             EOQualifier qualifier = relationship.qualifierWithSourceRow(database.snapshotForGlobalID(keyGID));
+                                             EOFetchSpecification relationshipFetchSpec = new EOFetchSpecification(entityName, qualifier, null);
+                                             EOAdaptorChannel channel = databaseContext.availableChannel().adaptorChannel();
+                                             channel.openChannel();
+                                             try {
+                                                 channel.selectAttributes(relationship.destinationEntity().attributesToFetch(), relationshipFetchSpec, false, relationship.destinationEntity());
+                                                 NSDictionary nextRow;
+                                                 NSDictionary destinationSnapshot = null;
+                                                 do {
+                                                     destinationSnapshot = channel.fetchRow();
+                                                     if (destinationSnapshot != null) {
+                                                         EOGlobalID destinationGID = relationship.destinationEntity().globalIDForRow(destinationSnapshot);
+                                                         newDestinationGIDs.addObject(destinationGID);
+                                                     }
+                                                     else {
+                                                         destinationSnapshot = null;
+                                                     }
+                                                 }
+                                                 while (destinationSnapshot != null);
+                                             }
+                                             finally {
+                                                 channel.cancelFetch();
+                                             }
+
+                                             NSArray objectsNotInDatabase = ERXArrayUtilities.arrayMinusArray(originalDestinationGIDs, newDestinationGIDs);
+                                             if (objectsNotInDatabase.count() > 0) {
+                                                 mismatches.addObject(gid + "." + relationshipName + " has entries not in the database: " + objectsNotInDatabase);
+                                             }
+                                             NSArray objectsNotInMemory = ERXArrayUtilities.arrayMinusArray(newDestinationGIDs, originalDestinationGIDs);
+                                             if (objectsNotInMemory.count() > 0) {
+                                                 mismatches.addObject(gid + "." + relationshipName + " is missing entries in the database: " + objectsNotInMemory);
+                                             }
+                                         }
+                                     }
+                                 }
+                             }
+                         }
+                         verifiedDatabases.addObject(database);
+                     }
+                 }
+                 finally {
+                     databaseContext.unlock();
+                 }
+             }
+         }
+         return mismatches;
      }
-
- 	/**
- 	 * In a multi-OSC or multi-instance scenario, when there are bugs, it is possible for the snapshots to become out of
- 	 * sync with the database. It is useful to have some way to determine when exactly this condition occurs for writing
- 	 * test cases.
- 	 *
- 	 * @return a set of strings that describe the mismatches that occurred
- 	 */
- 	public static NSSet verifyAllSnapshots() {
- 		NSMutableSet mismatches = new NSMutableSet();
- 		NSMutableSet verifiedDatabases = new NSMutableSet();
- 		EOEditingContext editingContext = ERXEC.newEditingContext();
- 		EOModelGroup modelGroup = EOModelGroup.defaultGroup();
- 		Enumeration modelsEnum = modelGroup.models().objectEnumerator();
- 		while (modelsEnum.hasMoreElements()) {
- 			EOModel model = (EOModel) modelsEnum.nextElement();
- 			EODatabaseContext databaseContext = null;
- 			try {
- 				databaseContext = EODatabaseContext.registeredDatabaseContextForModel(model, editingContext);
- 			}
- 			catch (IllegalStateException e) {
- 				log.warn("Model " + model.name() + " failed: " + e.getMessage());
- 			}
- 			if (databaseContext != null) {
- 				databaseContext.lock();
- 				try {
- 					EODatabase database = databaseContext.database();
- 					if (!verifiedDatabases.containsObject(database)) {
- 						Enumeration gidEnum = database.snapshots().keyEnumerator();
- 						while (gidEnum.hasMoreElements()) {
- 							EOGlobalID gid = (EOGlobalID) gidEnum.nextElement();
- 							if (gid instanceof EOKeyGlobalID) {
- 								EOEnterpriseObject eo = null;
- 								EOKeyGlobalID keyGID = (EOKeyGlobalID) gid;
- 								String entityName = keyGID.entityName();
- 								EOEntity entity = modelGroup.entityNamed(entityName);
- 								NSDictionary snapshot = database.snapshotForGlobalID(gid);
- 								if (snapshot != null) {
- 									EOQualifier gidQualifier = entity.qualifierForPrimaryKey(entity.primaryKeyForGlobalID(gid));
- 									EOFetchSpecification gidFetchSpec = new EOFetchSpecification(entityName, gidQualifier, null);
-
- 									NSMutableDictionary databaseSnapshotClone;
- 									NSMutableDictionary memorySnapshotClone = snapshot.mutableClone();
- 									EOAdaptorContext context;
- 									EOAdaptorChannel channel = databaseContext.availableChannel().adaptorChannel();
- 									channel.openChannel();
- 									channel.selectAttributes(entity.attributesToFetch(), gidFetchSpec, false, entity);
- 									NSDictionary nextRow;
- 									try {
- 										databaseSnapshotClone = channel.fetchRow().mutableClone();
- 									}
- 									finally {
- 										channel.cancelFetch();
- 									}
- 									// gidFetchSpec.setRefreshesRefetchedObjects(true);
- 									// NSArray databaseEOs = editingContext.objectsWithFetchSpecification(gidFetchSpec);
- 									if (databaseSnapshotClone == null) {
- 										mismatches.addObject(gid + " was deleted in the database, but the snapshot still exists: " + memorySnapshotClone);
- 									}
- 									else {
- 										// NSMutableDictionary refreshedSnapshotClone =
- 										// database.snapshotForGlobalID(gid).mutableClone();
- 										ERXDictionaryUtilities.removeMatchingEntries(memorySnapshotClone, databaseSnapshotClone);
- 										if (databaseSnapshotClone.count() > 0 || memorySnapshotClone.count() > 0) {
- 											mismatches.addObject(gid + " doesn't match the database: original = " + memorySnapshotClone + "; database = " + databaseSnapshotClone);
- 										}
- 										eo = (EOEnterpriseObject) editingContext.objectsWithFetchSpecification(gidFetchSpec).objectAtIndex(0);
- 									}
- 								}
-
- 								if (eo != null) {
- 									Enumeration relationshipsEnum = entity.relationships().objectEnumerator();
- 									while (relationshipsEnum.hasMoreElements()) {
- 										EORelationship relationship = (EORelationship) relationshipsEnum.nextElement();
- 										String relationshipName = relationship.name();
- 										NSArray originalDestinationGIDs = database.snapshotForSourceGlobalID(keyGID, relationshipName);
- 										if (originalDestinationGIDs != null) {
- 											NSMutableArray newDestinationGIDs = new NSMutableArray();
- 											EOQualifier qualifier = relationship.qualifierWithSourceRow(database.snapshotForGlobalID(keyGID));
- 											EOFetchSpecification relationshipFetchSpec = new EOFetchSpecification(entityName, qualifier, null);
- 											EOAdaptorChannel channel = databaseContext.availableChannel().adaptorChannel();
- 											channel.openChannel();
- 											try {
- 												channel.selectAttributes(relationship.destinationEntity().attributesToFetch(), relationshipFetchSpec, false, relationship.destinationEntity());
- 												NSDictionary nextRow;
- 												NSDictionary destinationSnapshot = null;
- 												do {
- 													destinationSnapshot = channel.fetchRow();
- 													if (destinationSnapshot != null) {
- 														EOGlobalID destinationGID = relationship.destinationEntity().globalIDForRow(destinationSnapshot);
- 														newDestinationGIDs.addObject(destinationGID);
- 													}
- 													else {
- 														destinationSnapshot = null;
- 													}
- 												}
- 												while (destinationSnapshot != null);
- 											}
- 											finally {
- 												channel.cancelFetch();
- 											}
-
- 											NSArray objectsNotInDatabase = ERXArrayUtilities.arrayMinusArray(originalDestinationGIDs, newDestinationGIDs);
- 											if (objectsNotInDatabase.count() > 0) {
- 												mismatches.addObject(gid + "." + relationshipName + " has entries not in the database: " + objectsNotInDatabase);
- 											}
- 											NSArray objectsNotInMemory = ERXArrayUtilities.arrayMinusArray(newDestinationGIDs, originalDestinationGIDs);
- 											if (objectsNotInMemory.count() > 0) {
- 												mismatches.addObject(gid + "." + relationshipName + " is missing entries in the database: " + objectsNotInMemory);
- 											}
- 										}
- 									}
- 								}
- 							}
- 						}
- 						verifiedDatabases.addObject(database);
- 					}
- 				}
- 				finally {
- 					databaseContext.unlock();
- 				}
- 			}
- 		}
- 		return mismatches;
- 	}
-}
\ No newline at end of file
+
+    /**
+     * @param ec an EOEditingContext
+     * @param count the number of primary keys you want EOF to generate
+     * @param entityName the Entity for whom the primary keys are generated
+     * @return the array of primary keys generated by the EOAdaptorChannel
+     * @see com.webobjects.eoaccess.EOAdaptorChannel#primaryKeysForNewRowsWithEntity(int, EOEntity)
+     * @author kieran
+     */
+    public static NSArray primaryKeysForNewRowsWithEntity(EOEditingContext ec, int count, String entityName) {
+        EOEntity entity = entityNamed(ec, entityName);
+        String modelName = entity.model().name();
+        NSArray primaryKeysArray = null;
+
+        boolean wasOpen = true;
+        EOAdaptorChannel channel = null;
+        int rows = 0;
+        ec.lock();
+        try {
+            EODatabaseContext dbc = EOUtilities.databaseContextForModelNamed(ec, modelName);
+            dbc.lock();
+            try {
+                channel = dbc.availableChannel().adaptorChannel();
+                wasOpen = channel.isOpen();
+                if(!wasOpen) {
+                    channel.openChannel();
+                }
+                channel.adaptorContext().beginTransaction();
+                try {
+                    primaryKeysArray = channel.primaryKeysForNewRowsWithEntity(count, entity);
+                    channel.adaptorContext().commitTransaction();
+                } catch(RuntimeException ex) {
+                    channel.adaptorContext().rollbackTransaction();
+                    throw ex;
+                }
+            } finally {
+                if(!wasOpen) {
+                    channel.closeChannel();
+                }
+                dbc.unlock();
+            }
+        } finally {
+            ec.unlock();
+        }
+        return primaryKeysArray;
+    }
+
+    /**
+     * Inserts a raw row. You are responsible to ensure it has a new valid primary key
+     * and that the dictionary contains valid attribute keys and valid values.
+     * There is no editing context or validation going on here.
+     * This is suitable only for massive bulk inserts where regular convenient EOF
+     * creation and saving in editing contexts does not meet the performance requirements.
+     * This should only be used where profiling shows that you need to go to this extreme.
+     * @see EOAdaptorChannel#insertRow(NSDictionary, EOEntity)
+     * @param ec
+     * @param rawRow
+     * @param entityName
+     * @return 1
+     * @author kieran
+     */
+    public static int insertRawRowForEntity(EOEditingContext ec, NSDictionary rawRow, String entityName){
+        EOEntity entity = entityNamed(ec, entityName);
+        String modelName = entity.model().name();
+
+        boolean wasOpen = true;
+        EOAdaptorChannel channel = null;
+        int rows = 0;
+        ec.lock();
+        try {
+            EODatabaseContext dbc = EOUtilities.databaseContextForModelNamed(ec, modelName);
+            dbc.lock();
+            try {
+                channel = dbc.availableChannel().adaptorChannel();
+                wasOpen = channel.isOpen();
+                if(!wasOpen) {
+                    channel.openChannel();
+                }
+                channel.adaptorContext().beginTransaction();
+                try {
+                    channel.insertRow(rawRow, entity);
+                    channel.adaptorContext().commitTransaction();
+                } catch(RuntimeException ex) {
+                    channel.adaptorContext().rollbackTransaction();
+                    throw ex;
+                }
+            } finally {
+                if(!wasOpen) {
+                    channel.closeChannel();
+                }
+                dbc.unlock();
+            }
+        } finally {
+            ec.unlock();
+        }
+        // TODO : The JDBCChannel concrete subclass has a rowsProcessedCount, so perhaps use that
+        return 1;
+    }
+}

On Dec 19, 2007, at 2:20 PM, Mike Schrag wrote:

HTH, Kieran
*cough*submittoWonder*cough*

ms

 _______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list      (email@hidden)
Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden

References: 
 >Batch inserts (From: Charles Koppelman <email@hidden>)
 >Re: Batch inserts (From: Kieran Kelleher <email@hidden>)
 >Re: Batch inserts (From: Mike Schrag <email@hidden>)

  • Prev by Date: Re: Batch inserts
  • Next by Date: Re: Batch inserts
  • Previous by thread: Re: Batch inserts
  • Next by thread: Re: Batch inserts
  • Index(es):
    • Date
    • Thread