/// <inheritdoc />
        public async Task <TEntity> GetAsync(object id)
        {
            var aggregateRoot = AggregateFactory.Build(typeof(TEntity));

            var snapshot = await _snapshotReader.ReadSnapshot(id, typeof(TEntity));

            if (snapshot != null)
            {
                aggregateRoot.RestoreSnapshot(snapshot);
            }

            var streamName = StreamNameResolver.Resolve(id, typeof(TEntity));

            var slice = GetEventSlice(_connection, streamName, aggregateRoot.CurrentVersion == -1 ? StreamPosition.Start : aggregateRoot.CurrentVersion + 1);

            if (slice.Status == SliceReadStatus.StreamDeleted || slice.Status == SliceReadStatus.StreamNotFound)
            {
                return(await Task.FromResult(default(TEntity)));
            }

            aggregateRoot.LoadFromHistory(slice.Events.ToDomainEvent());

            while (!slice.IsEndOfStream)
            {
                slice = GetEventSlice(_connection, streamName, slice.NextEventNumber);
                aggregateRoot.LoadFromHistory(slice.Events.ToDomainEvent());
            }

            _unitOfWork.Track(aggregateRoot);

            return((TEntity)aggregateRoot);
        }
        /// <inheritdoc />
        public async Task <Snapshot> ReadSnapshot(object id, Type aggregateType)
        {
            var snapshot = await _connection.ReadEventAsync(StreamNameResolver.ResolveForSnapshot(id, aggregateType), StreamPosition.End, true);

            if (NotAnySnapshotExists(snapshot))
            {
                return(await Task.FromResult <Snapshot>(null));
            }

            return((Snapshot)JsonConvert.DeserializeObject(
                       // ReSharper disable once PossibleInvalidOperationException
                       Encoding.UTF8.GetString(snapshot.Event.Value.Event.Data), TypeResolver.ResolveSnapshotType(snapshot.Event.Value.Event.EventType)));
        }
        /// <inheritdoc />
        public async Task TakeSnapshotIfNeed(IAggregateRoot aggregate)
        {
            var lastSnapshotVersion = -1L;
            var lastSnapshot        = await _connection.ReadEventAsync(StreamNameResolver.ResolveForSnapshot(aggregate), StreamPosition.End, true);

            if (AnySnapshotExists(lastSnapshot))
            {
                lastSnapshotVersion = lastSnapshot.Event.GetValueOrDefault().OriginalEventNumber;
            }

            if (NeedToTakeSnapshot(aggregate, lastSnapshotVersion))
            {
                await TakeSnapshot(_connection, aggregate);
            }
        }