构建IQueryable <T>,然后将其附加到DbSet <T>

时间:2019-09-23 05:00:05

标签: c# database linq linq-to-sql entity-framework-core

我的问题是 我可以在没有IQueryble<T>的情况下构建DbSet<T>吗? 然后将IQueryable<T>传递到将IQueryable<T>附加到DbSet<T>的方法上?

示例:

    public class Querying<T>
    {
         public T BuildQuery()
         {
            return Enumerable.Empty<T>().AsQueryable().Where(...);
         }
    }

    public class DatabaseContext<T>:DbContext
    {
        DbSet<T> _set;
        public List<T> ExecuteQuery(Querying<T> query)
        {
              return _set.AttachQuery(query.BuildQuery()).ToList();
        }
    }

1 个答案:

答案 0 :(得分:0)

using System;
using System.Linq;
using System.Linq.Expressions;

namespace QueryTest
{
    internal static class Program
    {
        private class ReplaceConstantVisitor : ExpressionVisitor
        {
            public object OldValue { get; }

            public object NewValue { get; }

            public ReplaceConstantVisitor(object oldValue, object newValue)
            {
                OldValue = oldValue;
                NewValue = newValue;
            }

            protected override Expression VisitConstant(ConstantExpression node)
            {
                if (node.Value == OldValue)
                {
                    return Expression.Constant(NewValue);
                }

                return base.VisitConstant(node);
            }
        }

        public static IQueryable<TQuery> ReplaceSource<TQuery, TSource>(this IQueryable<TQuery> query, IQueryable<TSource> source)
        {
            var exp = query.Expression;

            while (exp is MethodCallExpression m)
            {
                exp = m.Arguments[0];
            }

            if (!(exp is ConstantExpression oldSource))
            {
                throw new ArgumentException();
            }

            var newExp = new ReplaceConstantVisitor(oldSource.Value, source).Visit(query.Expression);

            return source.Provider.CreateQuery<TQuery>(newExp);
        }

        internal static void Main(string[] args)
        {
            var oldSource = new int[] { }.AsQueryable();

            var query =
                from i in oldSource
                where i > 5
                select $"{i * 2}";

            var newSource = new int[] { 1, 3, 5, 7, 9 }.AsQueryable();

            var newQuery = query.ReplaceSource(newSource);

            Console.WriteLine(string.Join(", ", newQuery));  //14, 18
        }
    }
}