/// <summary>
        /// Параллельная обработка перечисления на разных сессиях.
        /// </summary>
        /// <typeparam name="TSrc">Тип данных.</typeparam>
        /// <typeparam name="T">Тип результата.</typeparam>
        /// <param name="src">Перечисление.</param>
        /// <param name="parallelFunc">Функция обоработки.</param>
        /// <returns>Результат.</returns>
        protected async ValueTask <T[]> ParallelizeOnSessions <TSrc, T>(IEnumerable <TSrc> src, Func <IEsentSession, TSrc, T> parallelFunc)
        {
            ValueTask <T> Do(IEsentSession session, TSrc el)
            {
                return(session.Run(() => parallelFunc(session, el)));
            }

            if (src == null)
            {
                throw new ArgumentNullException(nameof(src));
            }
            if (parallelFunc == null)
            {
                throw new ArgumentNullException(nameof(parallelFunc));
            }
            var tasks     = new List <ValueTask <T> >();
            var toDispose = new CompositeDisposable(null);

            try
            {
                foreach (var el in src)
                {
                    var session = await EsentProvider.GetSecondarySessionAndUse();

                    toDispose.AddDisposable(session.usage);
                    tasks.Add(Do(session.session, el));
                }
                return(await CoreTaskHelper.WhenAllValueTasks(tasks));
            }
            finally
            {
                toDispose.Dispose();
            }
        }
        private async Task <IList <IBoardPostEntity> > LoadEntities(IList <PostStoreEntityId> ids, PostStoreLoadMode mode)
        {
            ValueTask <List <IBoardPostEntity> > DoLoad(IList <PostStoreEntityId> toLoad)
            {
                return(OpenSession(session =>
                {
                    var result = new List <IBoardPostEntity>();
                    var loadContext = CreateLoadContext(session, true, true);
                    var loadContextToDispose = loadContext;
                    using (loadContextToDispose)
                    {
                        foreach (var id in toLoad)
                        {
                            Api.MakeKey(loadContext.table.Session, loadContext.table, id.Id, MakeKeyGrbit.NewKey);
                            if (Api.TrySeek(loadContext.table.Session, loadContext.table, SeekGrbit.SeekEQ))
                            {
                                var r = LoadBoardEntity(session, ref loadContext, mode);
                                result.Add(r);
                            }
                        }
                    }
                    return result;
                }));
            }

            if (ids == null)
            {
                throw new ArgumentNullException(nameof(ids));
            }
            mode = mode ?? DefaultLoadMode;

            IList <IBoardPostEntity> loaded;

            if (ids.Count > 4)
            {
                var toLoad      = ids.DistributeToProcess(3);
                var tasks       = toLoad.Select(DoLoad).ToArray();
                var taskResults = await CoreTaskHelper.WhenAllValueTasks(tasks);

                loaded = taskResults.SelectMany(r => r).ToList();
            }
            else
            {
                loaded = await DoLoad(ids);
            }

            if (mode.EntityLoadMode == PostStoreEntityLoadMode.Full)
            {
                await FillChildrenInLoadResult(loaded);
            }

            return(loaded);
        }
        private async ValueTask <Nothing> SetChildren(IBoardPostEntity entity)
        {
            if (entity == null)
            {
                return(Nothing.Value);
            }

            ValueTask <List <IBoardPostEntity> > DoLoad(IList <(PostStoreEntityId id, int counter)> toLoad)
            {
                return(OpenSession(session =>
                {
                    var result = new List <IBoardPostEntity>();
                    var loadContext = CreateLoadContext(session, true, true);
                    var loadContextToDispose = loadContext;
                    using (loadContextToDispose)
                    {
                        foreach (var id in toLoad)
                        {
                            Api.MakeKey(loadContext.table.Session, loadContext.table, id.id.Id, MakeKeyGrbit.NewKey);
                            if (Api.TrySeek(loadContext.table.Session, loadContext.table, SeekGrbit.SeekEQ))
                            {
                                var r = LoadBoardEntity(session, ref loadContext, FullLoadMode);
                                if (r is IBoardPostLight l)
                                {
                                    l.Counter = id.counter;
                                }
                                result.Add(r);
                            }
                        }
                    }
                    return result;
                }));
            }

            var collection       = entity as IBoardPostCollection;
            var threadCollection = entity as IBoardPageThreadCollection;

            if ((entity.EntityType == PostStoreEntityType.Thread || entity.EntityType == PostStoreEntityType.ThreadPreview || entity.EntityType == PostStoreEntityType.Catalog || entity.EntityType == PostStoreEntityType.BoardPage) &&
                entity is IPostModelStoreChildrenLoadStageInfo loadStage && (collection?.Posts != null || threadCollection?.Threads != null) &&
                entity.StoreId != null)
            {
                if (loadStage.Stage == ChildrenLoadStageId.Completed)
                {
                    var childrenIds = await OpenSession(session0 => EnumEntityChildren(session0, entity.StoreId.Value));

                    IList <IBoardPostEntity> loaded;
                    if (childrenIds.Count > 4)
                    {
                        var toLoad      = childrenIds.DistributeToProcess(3);
                        var tasks       = toLoad.Select(DoLoad).ToArray();
                        var taskResults = await CoreTaskHelper.WhenAllValueTasks(tasks);

                        loaded = taskResults.SelectMany(r => r).ToList();
                    }
                    else
                    {
                        loaded = await DoLoad(childrenIds);
                    }

                    if (collection?.Posts != null)
                    {
                        IEnumerable <IBoardPost> toAdd;
                        if (entity.EntityType == PostStoreEntityType.Catalog)
                        {
                            int GetCatalogSequence(IBoardPost p)
                            {
                                if (p is IBoardPostEntityWithSequence s)
                                {
                                    return(s.OnPageSequence);
                                }
                                return(int.MaxValue);
                            }

                            toAdd = loaded.OfType <IBoardPost>().Deduplicate(p => p.Link, BoardLinkEqualityComparer.Instance).OrderBy(GetCatalogSequence);
                        }
                        else
                        {
                            toAdd = loaded.OfType <IBoardPost>().Deduplicate(p => p.Link, BoardLinkEqualityComparer.Instance).OrderBy(p => p.Link, BoardLinkComparer.Instance);
                        }
                        foreach (var item in toAdd)
                        {
                            collection.Posts.Add(item);
                        }
                    }
                    if (threadCollection?.Threads != null)
                    {
                        var toAdd = loaded.OfType <IThreadPreviewPostCollection>().Deduplicate(p => p.Link, BoardLinkEqualityComparer.Instance).OrderBy(p => p.OnPageSequence);
                        foreach (var item in toAdd)
                        {
                            threadCollection.Threads.Add(item);
                        }
                    }
                }
            }

            return(Nothing.Value);
        }