public override IAsyncEnumerable <Object> Execute(Object dataContext, OeQueryContext queryContext)
        {
            IEnumerable          enumerable;
            MethodCallExpression?countExpression = null;

            if (base.QueryCache.AllowCache)
            {
                enumerable = GetFromCache <Object>(queryContext, dataContext, out countExpression);
            }
            else
            {
                var        constantToVariableVisitor = new InMemoryConstantToVariableVisitor();
                Expression expression = queryContext.CreateExpression(out IReadOnlyDictionary <ConstantExpression, ConstantNode> constants);
                expression = new OeSingleNavigationVisitor(queryContext.EdmModel).Visit(expression);
                expression = new OeCollectionNavigationVisitor(queryContext.EdmModel).Visit(expression);
                expression = new NullPropagationVisitor().Visit(expression);
                expression = queryContext.TranslateSource(dataContext, expression);
                var func = (Func <IEnumerable>)Expression.Lambda(expression).Compile();
                enumerable = func();

                if (queryContext.IsQueryCount())
                {
                    countExpression = queryContext.CreateCountExpression(expression);
                }
            }

            if (countExpression != null)
            {
                var func = (Func <int>)Expression.Lambda(countExpression).Compile();
                queryContext.TotalCountOfItems = func();
            }

            return(Infrastructure.AsyncEnumeratorHelper.ToAsyncEnumerable(enumerable));
        }
        private IEnumerable GetFromCache <TResult>(OeQueryContext queryContext, Object dataContext, out MethodCallExpression?countExpression)
        {
            Cache.OeCacheContext   cacheContext   = queryContext.CreateCacheContext();
            Cache.OeQueryCacheItem?queryCacheItem = base.QueryCache.GetQuery(cacheContext);

            InMemoryExecutor executor;
            IReadOnlyList <Cache.OeQueryCacheDbParameterValue> parameterValues;

            if (queryCacheItem == null)
            {
                var        variableVisitor = new InMemoryConstantToVariableVisitor();
                Expression expression      = queryContext.CreateExpression(out IReadOnlyDictionary <ConstantExpression, ConstantNode> constants);
                expression = variableVisitor.Translate(expression, constants);
                expression = new OeSingleNavigationVisitor(queryContext.EdmModel).Visit(expression);
                expression = new OeCollectionNavigationVisitor(queryContext.EdmModel).Visit(expression);
                expression = new NullPropagationVisitor().Visit(expression);
                expression = new InMemorySourceVisitor(queryContext.EdmModel, variableVisitor.Parameters).Visit(expression);
                var query = (Func <IEnumerable>)Expression.Lambda(expression).Compile();

                if (queryContext.EntryFactory == null)
                {
                    countExpression = null;
                }
                else
                {
                    countExpression = queryContext.CreateCountExpression(expression);
                }

                cacheContext = queryContext.CreateCacheContext(variableVisitor.ConstantToParameterMapper);
                executor     = new InMemoryExecutor(query, variableVisitor.ParameterValues, variableVisitor.Parameters);
                base.QueryCache.AddQuery(cacheContext, executor, countExpression, queryContext.EntryFactory);
                parameterValues = variableVisitor.ParameterValues;
            }
            else
            {
                executor = (InMemoryExecutor)queryCacheItem.Query;
                queryContext.EntryFactory = queryCacheItem.EntryFactory;
                countExpression           = queryCacheItem.CountExpression;
                parameterValues           = cacheContext.ParameterValues;
            }

            if (!queryContext.IsQueryCount())
            {
                countExpression = null;
            }

            executor.Wait();
            executor.SetDataContext(dataContext);
            for (int i = 0; i < parameterValues.Count; i++)
            {
                executor[parameterValues[i].ParameterName] = parameterValues[i].ParameterValue;
            }
            return(executor);
        }
        public override TResult ExecuteScalar <TResult>(Object dataContext, OeQueryContext queryContext)
        {
            Cache.OeCacheContext   cacheContext   = queryContext.CreateCacheContext();
            Cache.OeQueryCacheItem?queryCacheItem = base.QueryCache.GetQuery(cacheContext);

            InMemoryScalarExecutor <TResult> executor;
            IReadOnlyList <Cache.OeQueryCacheDbParameterValue> parameterValues;

            if (queryCacheItem == null)
            {
                var        variableVisitor = new InMemoryConstantToVariableVisitor();
                Expression expression      = queryContext.CreateExpression(out IReadOnlyDictionary <ConstantExpression, ConstantNode> constants);
                expression = variableVisitor.Translate(expression, constants);
                expression = new OeSingleNavigationVisitor(queryContext.EdmModel).Visit(expression);
                expression = new OeCollectionNavigationVisitor(queryContext.EdmModel).Visit(expression);
                expression = new NullPropagationVisitor().Visit(expression);
                expression = queryContext.TranslateSource(dataContext, expression);
                var query = (Func <TResult>)Expression.Lambda(expression).Compile();

                cacheContext = queryContext.CreateCacheContext(variableVisitor.ConstantToParameterMapper);
                executor     = new InMemoryScalarExecutor <TResult>(query, variableVisitor.ParameterValues, variableVisitor.Parameters);
                base.QueryCache.AddQuery(cacheContext, (query, variableVisitor.Parameters), null, queryContext.EntryFactory);
                parameterValues = variableVisitor.ParameterValues;
            }
            else
            {
                executor = (InMemoryScalarExecutor <TResult>)queryCacheItem.Query;
                queryContext.EntryFactory = queryCacheItem.EntryFactory;
                parameterValues           = cacheContext.ParameterValues;
            }

            lock (executor)
            {
                for (int i = 0; i < parameterValues.Count; i++)
                {
                    executor[parameterValues[i].ParameterName] = parameterValues[i].ParameterValue;
                }
                return(executor.Execute());
            }
        }