/// <summary>
        /// Creates or updates the snapshot for the given aggregate root.
        /// </summary>
        /// <param name="aggregateRoot">The aggregate root on which the snapshot is created or updated.</param>
        public override void CreateOrUpdateSnapshot(ISourcedAggregateRoot aggregateRoot)
        {
            var snapshot           = aggregateRoot.CreateSnapshot();
            var dataObj            = _acDomain.CreateFromAggregateRoot(aggregateRoot);
            var insertOrUpdateData = new PropertyBag(dataObj);
            var key = new EventNumberSnapshotMappingKey(aggregateRoot.GetType().AssemblyQualifiedName, aggregateRoot.Id);

            if (this.HasSnapshot(aggregateRoot.GetType(), aggregateRoot.Id))
            {
                var aggregateRootTypeName = aggregateRoot.GetType().AssemblyQualifiedName;
                var aggregateRootId       = aggregateRoot.Id;
                ISpecification <SnapshotDataObject> spec = Specification <SnapshotDataObject> .Eval(
                    p => p.AggregateRootType == aggregateRootTypeName &&
                    p.AggregateRootId == aggregateRootId);

                this.SnapshotStorage.Update <SnapshotDataObject>(insertOrUpdateData, spec);
                this.Committed = false;
                if (_snapshotMapping.ContainsKey(key))
                {
                    _snapshotMapping[key] = snapshot;
                }
                else
                {
                    _snapshotMapping.Add(key, snapshot);
                }
            }
            else
            {
                this.SnapshotStorage.Insert <SnapshotDataObject>(insertOrUpdateData);
                this.Committed = true;
                _snapshotMapping.Add(key, snapshot);
            }
        }
        /// <summary>
        /// Returns a <see cref="System.Boolean"/> value which indicates whether the snapshot
        /// exists for the aggregate root with the given type and identifier.
        /// </summary>
        /// <param name="aggregateRootType">The type of the aggregate root.</param>
        /// <param name="id">The identifier of the aggregate root.</param>
        /// <returns>True if the snapshot exists, otherwise false.</returns>
        public override bool HasSnapshot(Type aggregateRootType, Guid id)
        {
            var key = new EventNumberSnapshotMappingKey(aggregateRootType.AssemblyQualifiedName, id);

            if (_snapshotMapping.ContainsKey(key))
            {
                return(true);
            }
            var aggregateRootTypeName = aggregateRootType.AssemblyQualifiedName;
            ISpecification <SnapshotDataObject> spec = Specification <SnapshotDataObject> .Eval(
                p => p.AggregateRootType == aggregateRootTypeName && p.AggregateRootId == id);

            var snapshotRecordCnt = this.SnapshotStorage.GetRecordCount <SnapshotDataObject>(spec);

            return(snapshotRecordCnt > 0);
        }
        /// <summary>
        /// Gets the snapshot for the aggregate root with the given type and identifier.
        /// </summary>
        /// <param name="aggregateRootType">The type of the aggregate root.</param>
        /// <param name="id">The identifier of the aggregate root.</param>
        /// <returns>The snapshot instance.</returns>
        public override ISnapshot GetSnapshot(Type aggregateRootType, Guid id)
        {
            var key = new EventNumberSnapshotMappingKey(aggregateRootType.AssemblyQualifiedName, id);

            if (_snapshotMapping.ContainsKey(key))
            {
                return(_snapshotMapping[key]);
            }
            var aggregateRootTypeName = aggregateRootType.AssemblyQualifiedName;
            ISpecification <SnapshotDataObject> spec = Specification <SnapshotDataObject> .Eval(
                p => p.AggregateRootType == aggregateRootTypeName && p.AggregateRootId == id);

            var dataObj = this.SnapshotStorage.SelectFirstOnly <SnapshotDataObject>(spec);

            if (dataObj == null)
            {
                return(null);
            }
            var snapshot = _acDomain.ExtractSnapshot(dataObj);

            this._snapshotMapping.Add(key, snapshot);
            return(snapshot);
        }