/// <summary>
        /// Get all entities in branch by branchId. If the branch sorted, it returns from sorted branch.
        /// </summary>
        /// <param name="branchId">Id to identify branch</param>
        /// <param name="groups">Groups are values to create branch keys</param>
        /// <returns>Found entities</returns>
        public async Task <IEnumerable <T> > GetAsync(string branchId, params string[] groups)
        {
            IBranch <T> branch = _branches.Find(b => b.GetBranchId() == branchId);

            if (branch == default)
            {
                throw new KeyNotFoundException($"branchId not found: {branchId}. Possible branches: {String.Join(", ", _branches.Select(i => i.GetBranchKey()))}");
            }

            if (((IBranchInternal <T>)branch).IsSortable())
            {
                return(await GetSortedAsync(branch, double.MinValue, double.MaxValue, 0, long.MaxValue, groups));
            }
            else
            {
                RedisValue[] ids = await _redisDatabase.SetMembersAsync(branch.GetBranchKey(groups)).ConfigureAwait(false);

                List <T> resultList = new List <T>();
                foreach (RedisValue id in ids)
                {
                    resultList.Add((await _redisDatabase.HashGetAllAsync($"{typeof(T).Name}:data:{id}").ConfigureAwait(false)).ConvertFromHashEntryList <T>());
                }
                return(resultList);
            }
        }
        /// <summary>
        /// Private helper method to get sorted branch items.
        /// </summary>
        /// <param name="branch">Sorted Branch to query</param>
        /// <param name="from">Elements have score from</param>
        /// <param name="to">Elements have score to</param>
        /// <param name="skip">Skip elements</param>
        /// <param name="take">Take elements</param>
        /// <param name="groups">Groups values to be filtered</param>
        /// <returns>Filtered items</returns>
        private async Task <IEnumerable <T> > GetSortedAsync(IBranch <T> branch, double from, double to, long skip, long take, params string[] groups)
        {
            List <T> resultList = new List <T>();

            RedisValue[] ids = await _redisDatabase.SortedSetRangeByScoreAsync(branch.GetBranchKey(groups), from, to, Exclude.None, Order.Ascending, skip, take).ConfigureAwait(false);

            foreach (RedisValue id in ids)
            {
                resultList.Add((await _redisDatabase.HashGetAllAsync($"{typeof(T).Name}:data:{id}").ConfigureAwait(false)).ConvertFromHashEntryList <T>());
            }
            return(resultList);
        }
        /// <summary>
        /// Get entity by id.
        /// </summary>
        /// <param name="id">Id of Entity</param>
        /// <returns>Entity of repository</returns>
        public async Task <T> GetByIdAsync(string id)
        {
            IBranch <T> dataBranch = _branches.Find(i => i.GetBranchId() == BRANCH_DATA);

            if (dataBranch == default)
            {
                throw new KeyNotFoundException("Data Branch not found.");
            }
            string redisKey = dataBranch.GetBranchKey().Replace("{propertyValue}", id);

            HashEntry[] hashSet = (await _redisDatabase.HashGetAllAsync(redisKey).ConfigureAwait(false));
            return(hashSet.Length == 0 ? null : hashSet.ConvertFromHashEntryList <T>());
        }
        /// <summary>
        /// Get entity counts in the branch. If the branch is not sorted throws ArgumentException.
        /// </summary>
        /// <param name="branchId">Id to identify branch</param>
        /// <param name="from">Score from</param>
        /// <param name="to">Score to</param>
        /// <param name="groups">Groups are values to create branch keys.</param>
        /// <returns>Count of entities meet with criterias</returns>
        public async Task <long> CountAsync(string branchId, double from, double to, params string[] groups)
        {
            IBranch <T> branch = _branches.Find(b => b.GetBranchId() == branchId);

            if (branch == default)
            {
                throw new KeyNotFoundException($"branchId not found: {branchId}. Possible branches: {String.Join(", ", _branches.Select(i => i.GetBranchKey()))}");
            }

            if (((IBranchInternal <T>)branch).IsSortable())
            {
                return(await CountSortedAsync(branch, from, to, groups));
            }
            else
            {
                throw new ArgumentException($"Branch({branchId}:{branch.GetBranchKey()} is not a sortable branch.)");
            }
        }
        /// <summary>
        /// Get entity counts in the branch. If the branch sorted, it returns counts in the sorted branch.
        /// </summary>
        /// <param name="branchId">Id to identify branch</param>
        /// <param name="groups">Groups parameters</param>
        /// <returns>Count of entities meet with criterias</returns>
        public async Task <long> CountAsync(string branchId, params string[] groups)
        {
            IBranch <T> branch = _branches.Find(b => b.GetBranchId() == branchId);

            if (branch == default)
            {
                throw new KeyNotFoundException($"branchId not found: {branchId}. Possible branches: {String.Join(", ", _branches.Select(i => i.GetBranchKey()))}");
            }

            if (((IBranchInternal <T>)branch).IsSortable())
            {
                return(await CountSortedAsync(branch, double.MinValue, double.MaxValue, groups));
            }
            else
            {
                return(await _redisDatabase.SetLengthAsync(branch.GetBranchKey(groups)).ConfigureAwait(false));
            }
        }
 /// <summary>
 /// Private helper method to get entity counts in the sorted branch.
 /// </summary>
 /// <param name="branch">Sorted Branch to query</param>
 /// <param name="from">Elements have score from</param>
 /// <param name="to">Elements have score to</param>
 /// <param name="groups">Groups values to be filtered</param>
 /// <returns>Counts of filtered items.</returns>
 private async Task <long> CountSortedAsync(IBranch <T> branch, double from, double to, params string[] groups)
 {
     return(await _redisDatabase.SortedSetLengthAsync(branch.GetBranchKey(groups), from, to).ConfigureAwait(false));
 }