This class is used with the db4o backend to record the key information about what changed in a transaction.
		/*-------------------------------------------------------------------*/
		/// <summary>
		/// Update the backend store.
		/// </summary>
		/// <param name="newbies">The newly created objects</param>
		/// <param name="dirtballs">The recently modified objects</param>
		/// <param name="goners">The recently deleted objects</param>
		/// <returns>true if all is well (successful save or nothing to save)</returns>
		public override bool Commit(
			HashSet<ICmObjectOrSurrogate> newbies, HashSet<ICmObjectOrSurrogate> dirtballs, HashSet<ICmObjectId> goners)
		{
			if (m_dbStore == null)
			{
				if (!ResumeDb4oConnectionAskingUser())
				{
					throw new NonRecoverableConnectionLostException();
				}
			}

			if (!GetCommitLock(newbies.Count != 0 || dirtballs.Count != 0 || goners.Count != 0))
				return true;
			try
			{
				List<ICmObjectSurrogate> foreignNewbies;
				List<ICmObjectSurrogate> foreignDirtballs;
				List<ICmObjectId> foreignGoners;
				if (GetUnseenForeignChanges(out foreignNewbies, out foreignDirtballs, out foreignGoners))
				{
					IUnitOfWorkService uowService = ((IServiceLocatorInternal) m_cache.ServiceLocator).UnitOfWorkService;
					IReconcileChanges reconciler = uowService.CreateReconciler(foreignNewbies, foreignDirtballs, foreignGoners);
					if (reconciler.OkToReconcileChanges())
					{
						reconciler.ReconcileForeignChanges();
						// And continue looping, in case there are by now MORE foreign changes!
					}
					else
					{
						uowService.ConflictingChanges(reconciler);
						return true;
					}
				}

				IEnumerable<CustomFieldInfo> cfiList;
				bool anyModifiedCustomFields;
				if (!HaveAnythingToCommit(newbies, dirtballs, goners, out anyModifiedCustomFields, out cfiList))
					return true;

				var commitData = new CommitData { Source = m_mySourceTag };
				int objectAddedIndex = 0;
				commitData.ObjectsDeleted = (from item in goners select item.Guid).ToArray();

				//m_dbStore.Ext().Purge();
				var generation = commitData.WriteGeneration = NextWriteGeneration;
				// we've seen our own change, and we use a semaphore to make sure there haven't been others since we checked.
				m_lastWriteGenerationSeen = generation;
				if (anyModifiedCustomFields)
				{
					var validKeys = new HashSet<string>();
					foreach (var customFieldInfo in cfiList)
					{
						validKeys.Add(customFieldInfo.Key);
						CustomFieldInfo oldInfo;
						if (m_myKnownCustomFields.TryGetValue(customFieldInfo.Key, out oldInfo))
						{
							if (oldInfo.Equals(customFieldInfo))
								continue; // unchanged
							m_dbStore.Delete(oldInfo);
						}
						m_dbStore.Store(customFieldInfo);
						m_myKnownCustomFields[customFieldInfo.Key] = customFieldInfo;
					}
					// Get rid of deleted ones. In Db4o, it is not enough just not to re-save them!
					foreach (CustomFieldInfo customField in m_dbStore.Query<CustomFieldInfo>())
					{
						if (!validKeys.Contains(customField.Key))
							m_dbStore.Delete(customField);
					}
				}

				// The ToArray() is so we can safely modify the collection. (Note: even before we added the
				// code to convert dirtballs to newbies, there was some mysterious case where .Net thinks we have modified the
				// collection. Maybe sometimes the dirtball is present as a surrogate and modifying it by Refreshing
				// somehow changes the hashset? Anyway, be cautious about removing the ToArray(), even if you find
				// a better way to handle the spurious dirtballs).
				foreach (var dirtball in dirtballs.ToArray())
				{
					long id;
					if (!m_idMap.TryGetValue(dirtball.Id, out id))
					{
						// pathologically, SaveAndForceNewestXmlForCmObjectWithoutUnitOfWork may pass newbies as dirtballs.
						newbies.Add(dirtball);
						dirtballs.Remove(dirtball);
						continue;
					}
					var realDbObj = (CmObjectSurrogate)m_dbStore.Ext().GetByID(id);
					m_dbStore.Ext().Refresh(realDbObj, Int32.MaxValue);
					realDbObj.Update(dirtball.Classname, dirtball.XMLBytes);
					m_dbStore.Store(realDbObj);
				}

				commitData.ObjectsAdded = new long[newbies.Count]; // after possibly adjusting newbies above
				commitData.ObjectsUpdated = (from item in dirtballs select item.Id.Guid).ToArray();

				// Enhance JohnT: possibly this could be sped up by taking advantage of the case where
				// newby is already a CmObjectSurrogate. This is probably only the case where we are
				// doing data migration or switching backends, however.

				foreach (var newby in newbies)
				{
					var newSurrogate = new CmObjectSurrogate(m_cache, newby.Id, newby.Classname, newby.XMLBytes);
					m_dbStore.Store(newSurrogate);
					commitData.ObjectsAdded[objectAddedIndex++] = m_dbStore.Ext().GetID(newSurrogate);
					MapId(newSurrogate);
				}

				foreach (var goner in goners)
				{
					var id = m_idMap[goner];
					var realDbObj = (CmObjectSurrogate)m_dbStore.Ext().GetByID(id);
					m_dbStore.Ext().Refresh(realDbObj, Int32.MaxValue);
					m_dbStore.Delete(realDbObj);
					m_idMap.Remove(goner);
				}
				if (m_modelVersionOverride != m_modelVersionNumber.m_modelVersionNumber)
				{
					m_modelVersionNumber.m_modelVersionNumber = m_modelVersionOverride;
					m_dbStore.Store(m_modelVersionNumber);
				}
				m_dbStore.Store(commitData);
				m_dbStore.Commit();
			}
			catch (Db4objects.Db4o.Ext.DatabaseClosedException)
			{
				if (!ResumeDb4oConnectionAskingUser())
				{
					throw new NonRecoverableConnectionLostException();
				}

				ReleaseCommitLock();
				// reattempt the commit.
				return Commit(newbies, dirtballs, goners);
			}
			catch (Exception err)
			{
				m_dbStore.Rollback();
				throw;
			}
			finally
			{
				ReleaseCommitLock();
			}
			return base.Commit(newbies, dirtballs, goners);
		}