protected ICommandData CreatePutEntityCommand(object entity, DocumentSession.DocumentMetadata documentMetadata)
        {
            var json       = ConvertEntityToJson(entity, documentMetadata.Metadata);
            var entityType = entity.GetType();


            //This fails to find the key if it's a dynamic object

            string key = null;

#if !NET_3_5
            if (entity is IDynamicMetaObjectProvider)
            {
                TryGetId(entity, out key);
            }
            else
#endif
            {
                var identityProperty = GetIdentityProperty(entityType);
                if (identityProperty != null)
                {
                    key = (string)identityProperty.GetValue(entity, null);
                }
            }
            var etag = UseOptimisticConcurrency ? documentMetadata.ETag : null;

            return(new PutCommandData
            {
                Document = json,
                Etag = etag,
                Key = key,
                Metadata = documentMetadata.Metadata,
            });
        }
        public T TrackEntity <T>(string key, JObject document, JObject metadata)
        {
            object entity;

            if (entitiesByKey.TryGetValue(key, out entity) == false)
            {
                entity = ConvertToEntity <T>(key, document, metadata);
            }
            else
            {
                // the local instnace may have been changed, we adhere to the current Unit of Work
                // instance, and return that, ignoring anything new.
                return((T)entity);
            }
            var etag = metadata.Value <string>("@etag");

            if (metadata.Value <bool>("Non-Authoritive-Information") &&
                AllowNonAuthoritiveInformation == false)
            {
                throw new NonAuthoritiveInformationException("Document " + key +
                                                             " returned Non Authoritive Information (probably modified by a transaction in progress) and AllowNonAuthoritiveInformation  is set to false");
            }
            entitiesAndMetadata[entity] = new DocumentSession.DocumentMetadata
            {
                OriginalValue    = document,
                Metadata         = metadata,
                OriginalMetadata = new JObject(metadata),
                ETag             = new Guid(etag),
                Key = key
            };
            entitiesByKey[key] = entity;
            return((T)entity);
        }
        protected DocumentSession.SaveChangesData PrepareForSaveChanges()
        {
            var result = new DocumentSession.SaveChangesData
            {
                Entities = new List <object>(),
                Commands = new List <ICommandData>()
            };

            TryEnlistInAmbientTransaction();
            DocumentSession.DocumentMetadata value = null;
            foreach (var key in (from deletedEntity in deletedEntities
                                 where entitiesAndMetadata.TryGetValue(deletedEntity, out value)
                                 select value.Key))
            {
                Guid?  etag = null;
                object existingEntity;
                DocumentSession.DocumentMetadata metadata = null;
                if (entitiesByKey.TryGetValue(key, out existingEntity))
                {
                    if (entitiesAndMetadata.TryGetValue(existingEntity, out metadata))
                    {
                        etag = metadata.ETag;
                    }
                    entitiesAndMetadata.Remove(existingEntity);
                    entitiesByKey.Remove(key);
                }

                etag = UseOptimisticConcurrency ? etag : null;
                result.Entities.Add(existingEntity);

                foreach (var deleteListener in deleteListeners)
                {
                    deleteListener.BeforeDelete(key, existingEntity, metadata != null ? metadata.Metadata : null);
                }

                result.Commands.Add(new DeleteCommandData
                {
                    Etag = etag,
                    Key  = key,
                });
            }
            deletedEntities.Clear();
            foreach (var entity in entitiesAndMetadata.Where(pair => EntityChanged(pair.Key, pair.Value)))
            {
                foreach (var documentStoreListener in storeListeners)
                {
                    documentStoreListener.BeforeStore(entity.Value.Key, entity.Key, entity.Value.Metadata);
                }
                result.Entities.Add(entity.Key);
                if (entity.Value.Key != null)
                {
                    entitiesByKey.Remove(entity.Value.Key);
                }
                result.Commands.Add(CreatePutEntityCommand(entity.Key, entity.Value));
            }

            return(result);
        }
        protected bool EntityChanged(object entity, DocumentSession.DocumentMetadata documentMetadata)
        {
            if (documentMetadata == null)
            {
                return(true);
            }
            var newObj           = ConvertEntityToJson(entity, documentMetadata.Metadata);
            var equalityComparer = new JTokenEqualityComparer();

            return(equalityComparer.Equals(newObj, documentMetadata.OriginalValue) == false ||
                   equalityComparer.Equals(documentMetadata.Metadata, documentMetadata.OriginalMetadata) == false);
        }