// Protected methods

        protected virtual async Task ProcessBatch(List <BatchItem <TKey, TEntity> > batch, CancellationToken cancellationToken)
        {
            await using var dbContext = CreateDbContext();
            var keys = new HashSet <TKey>();

            foreach (var item in batch)
            {
                if (!item.TryCancel(cancellationToken))
                {
                    keys.Add(item.Input);
                }
            }
            var pEntity  = Expression.Parameter(typeof(TEntity), "e");
            var eKey     = KeyExtractorExpressionBuilder.Invoke(pEntity);
            var eBody    = Expression.Call(Expression.Constant(keys), ContainsMethod, eKey);
            var eLambda  = (Expression <Func <TEntity, bool> >)Expression.Lambda(eBody, pEntity);
            var query    = QueryTransformer.Invoke(dbContext.Set <TEntity>().Where(eLambda));
            var entities = await query
                           .ToDictionaryAsync(KeyExtractor, cancellationToken)
                           .ConfigureAwait(false);

            PostProcessor.Invoke(entities);

            foreach (var item in batch)
            {
                entities.TryGetValue(item.Input, out var entity);
                item.SetResult(Result.Value(entity) !, CancellationToken.None);
            }
        }