/// <summary>
        /// This makes sure that if the operatoin is for a Relation, that the source and destination items for the relation exist already
        /// in either the queue or the physical index itself.
        /// </summary>
        /// <param name="op"></param>
        /// <param name="idsinQueue"></param>
        private void EnsureRelationEntities(LinearHiveIndexOperation op, string[] idsinQueue)
        {
            if (op.IsRelation())
            {
                // Get the source and destination items from the Nh session
                var sourceNode = GetItem(op.Fields[FixedRelationIndexFields.SourceId].FieldValue.ToString(), idsinQueue);
                var destNode   = GetItem(op.Fields[FixedRelationIndexFields.DestinationId].FieldValue.ToString(), idsinQueue);

                // Check the Nh session is already aware of the items
                if (sourceNode == null || destNode == null)
                {
                    string extraMessage = string.Empty;
                    if (sourceNode == null)
                    {
                        extraMessage = "Source {0} cannot be found.\n".InvariantFormat(op.Fields[FixedRelationIndexFields.SourceId].FieldValue);
                    }
                    if (destNode == null)
                    {
                        extraMessage += "Destination {0} cannot be found.".InvariantFormat(op.Fields[FixedRelationIndexFields.DestinationId].FieldValue);
                    }
                    throw new InvalidOperationException(
                              "Before adding a relation between source {0} and destination {1}, you must call AddOrUpdate with those items or they must already exist in the datastore.\n{2}"
                              .InvariantFormat(op.Fields[FixedRelationIndexFields.SourceId].FieldValue, op.Fields[FixedRelationIndexFields.DestinationId].FieldValue, extraMessage));
                }
            }
        }
        /// <summary>
        /// Adds an index operation to the Queue, if the item already exists it is ignored.
        /// </summary>
        /// <param name="op"></param>
        public void EnqueueIndexOperation(LinearHiveIndexOperation op)
        {
            if (!_itemsToIndex.ShouldAddNewQueueItem(op))
            {
                return;
            }

            //before we process each item, we need to update all of the item ids if they haven't been set
            if (op.OperationType == IndexOperationType.Add && op.Entity != null)
            {
                //check if we should be creating Ids
                if (!_providerMetadata.IsPassthroughProvider)
                {
                    ExamineHelper.EnsureIds(op);
                }
            }

            _itemsToIndex.Add(op);
        }
        /// <summary>
        /// When the Entity is a Revision, this checks the previous revisions committed during this transaction to see if the status has actually changed,
        /// if it determines that no previous entry exists in memory for this transaction, it will look up the entity in the index to see if the
        /// status has changed. It then sets the status changed date accordingly on the TypedEntity and in the index fields.
        /// </summary>
        /// <param name="op"></param>
        /// <param name="revisionsCommitted"></param>
        /// <returns>Returns a Tuple of the updated TypedEntity and RevisionData</returns>
        private Tuple <TypedEntity, RevisionData> EnsureCorrectStatusChangedDate(LinearHiveIndexOperation op, IEnumerable <Tuple <TypedEntity, RevisionData> > revisionsCommitted)
        {
            dynamic      r  = op.Entity;
            TypedEntity  te = r.Item;
            RevisionData rd = r.MetaData;

            //find all previous TypedEntities in the committed list matching this one
            var previous = revisionsCommitted.Where(x => x.Item1.Id.Value.ToString() == te.Id.Value.ToString())
                           .OrderBy(x => x.Item1.UtcModified)
                           .LastOrDefault();
            SearchResult latestEntry = GetLatestEntry(r);

            if (previous == null && latestEntry != null && latestEntry.Fields.ContainsKey(FixedRevisionIndexFields.RevisionStatusId) && latestEntry.Fields[FixedRevisionIndexFields.RevisionStatusId] != rd.StatusType.Id.Value.ToString())
            {
                //if there's nothing in memory but there's a previously saved entry with a different status id, then update the date
                te.UtcStatusChanged = rd.UtcCreated;
                op.Fields[FixedIndexedFields.UtcStatusChanged] = new ItemField(te.UtcStatusChanged.UtcDateTime)
                {
                    DataType = FieldDataType.DateTime
                };
            }
            else if (previous != null && previous.Item2.StatusType.Id.Value.ToString() != rd.StatusType.Id.Value.ToString())
            {
                //its changed in memory so update the date
                te.UtcStatusChanged = rd.UtcCreated;
                op.Fields[FixedIndexedFields.UtcStatusChanged] = new ItemField(te.UtcStatusChanged.UtcDateTime)
                {
                    DataType = FieldDataType.DateTime
                };
            }
            else if (latestEntry != null)
            {
                //the status hasn't changed and the entity is not new, set to latest entries status changed
                te.UtcStatusChanged = ExamineHelper.FromExamineDateTime(latestEntry.Fields, FixedIndexedFields.UtcStatusChanged).Value;
                op.Fields[FixedIndexedFields.UtcStatusChanged] = new ItemField(te.UtcStatusChanged.UtcDateTime)
                {
                    DataType = FieldDataType.DateTime
                };
            }
            return(new Tuple <TypedEntity, RevisionData>(te, rd));
        }