表达式树转SQL(自己实现IQueryable类型)

1.数据库辅助类

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ExpTreeToSQL
{
    public class DbHelper : IDisposable
    {
        private SqlConnection _conn;

        public bool Connect()
        {
            _conn = new SqlConnection
            {
                //connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=ServerWorkerTrack;User ID=sa;Password=982514" providerName="System.Data.SqlClient"/>
                ConnectionString = @"Data Source=.\SQLEXPRESS;Initial Catalog=testDb;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"
            };
            _conn.Open();
            return true;
        }

        public void ExecuteSql(string sql)
        {
            var cmd = new SqlCommand(sql, _conn);
            cmd.ExecuteNonQuery();
        }

        public List GetPerson(string sql)
        {
            var person = new List();
            var cmd = new SqlCommand(sql, _conn);
            var sdr = cmd.ExecuteReader();
            while (sdr.Read())
            {
                person.Add(new T_Person
                {
                    ID = sdr.GetInt64(0),
                    Name = sdr.GetString(1),
                    Age = sdr.GetInt32(2),
                    Sex = sdr.GetString(3)
                });
            }
            return person;
        }

        public void Dispose()
        {
            _conn.Close();
            _conn = null;
        }
    }

    public class T_Person
    {
        public long ID { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public string Sex { get; set; }
    }

}

  

//表达式转SQL解析类


using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace ExpTreeToSQL
{
    class ExpressionTreeToSql
    {
        public static string VisitExpression(T enumerable, Expression expression, ref string sql)
        {
            //select头
            if (sql == string.Empty)
                sql = GenerateSelectHeader(enumerable);

            //递归解析Where(m => m.Name == "Frank")的代码
            //分情况为结果sql增加字符串
            switch (expression.NodeType)
            {
                case ExpressionType.Call:
                    MethodCallExpression method = expression as MethodCallExpression;
                    if (method != null)
                    {
                        //获得where这个字符串,也就是方法名
                        sql += method.Method.Name;

                        //继续解析,传入第二个方法参数{m => (m.Name == "Frank")}
                        VisitExpression(enumerable, method.Arguments[1], ref sql);
                    }
                    break;
                case ExpressionType.Quote:
                    UnaryExpression expUnary = expression as UnaryExpression;
                    if (expUnary != null)
                    {
                        VisitExpression(enumerable, expUnary.Operand, ref sql);
                    }
                    break;
                case ExpressionType.Lambda:
                    LambdaExpression expLambda = expression as LambdaExpression;
                    if (expLambda != null)
                    {
                        VisitExpression(enumerable, expLambda.Body, ref sql);
                    }
                    break;
                case ExpressionType.Equal:
                    BinaryExpression expBinary = expression as BinaryExpression;
                    if (expBinary != null)
                    {
                        var left = expBinary.Left;
                        var right = expBinary.Right;
                        sql += " " + left.ToString().Split('.')[1] + " = '" + right.ToString().Replace("\"", "") + "'";
                    }
                    break;
                default:
                    throw new NotSupportedException(string.Format("不支持这种表达式: {0}", expression.NodeType));
            }
            return sql;
        }

        //半硬编码的select
        public static string GenerateSelectHeader(T type)
        {
            return string.Format("select * from {0} ", typeof(T).Name);
        }
    }
}
//自己实现的IQueryProvider类型


using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace ExpTreeToSQL
{
    public class MyQueryProvider : IQueryProvider
    {
        public IQueryable CreateQuery(Expression expression)
        {
            throw new NotImplementedException();
        }
        public object Execute(Expression expression)
        {
            throw new NotImplementedException();
        }
        public IQueryable CreateQuery(Expression expression)
        {
            Console.WriteLine("建立一个查询,但不执行");
            return new MyIQueryable(expression, this);
        }

        public TResult Execute(Expression expression)
        {
            var sql = string.Empty;
            sql = ExpressionTreeToSql.VisitExpression(new T_Person(), expression, ref sql);
            Console.WriteLine(sql);

            Console.WriteLine(sql);

            using (var db = new DbHelper())
            {
                db.Connect();
                dynamic ret = db.GetPerson(sql);
                return (TResult)ret;
            }
        }
    }

}
 public class MyIQueryable : IQueryable
    {
        public IEnumerator GetEnumerator()
        {
            Console.WriteLine("开始取值");
            var result = Provider.Execute>(Expression);
            foreach (var item in result)
            {
                Console.WriteLine("发现一条合格的值");
                yield return item;
            }           
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            throw new NotImplementedException();
        }

        public Expression Expression { get; private set; }
        public Type ElementType { get; private set; }
        public IQueryProvider Provider { get; private set; }

        //不知道该写什么的构造函数
        public MyIQueryable(Expression exp, MyQueryProvider provider)
        {
            Expression = exp;
            ElementType = typeof(T);
            Provider = provider;
        }

        public MyIQueryable() : this(null, new MyQueryProvider())
        {
          Expression = Expression.Constant(this);

        // Expression=  Expression.Default(typeof(MyIQueryable));
        }
    }

测试代码:

 

 

  class Program
    {
        static void Main(string[] args)
        {
            using (var db = new DbHelper())
            {
                db.Connect();
                db.ExecuteSql("DELETE FROM T_Person");

                //主键自增
                db.ExecuteSql("INSERT INTO T_Person VALUES ('Frank',30,'M')");
                db.ExecuteSql("INSERT INTO T_Person VALUES ('Mary',99,'F')");

                //使用ADO.NET获得数据
                var person = db.GetPerson("select * from T_Person where Name = 'Frank'");

                foreach (var person1 in person)
                {
                    Console.WriteLine("结果的年龄是" + person1.Age);
                }
            }

            //自己的逻辑
            var myqueryable = new MyIQueryable();

            //这里传入什么都没区别,反正里面是硬编码的
            var ret = myqueryable.Where(m => m.Name == "Frank");

            foreach (var person1 in ret)
            {
                Console.WriteLine("结果的年龄是" + person1.Age);
            }

            var seq = Enumerable.Range(0, 10);
            var a = seq.First();
            var b = seq.Select(s => s / 2 == 0);

            Console.ReadKey();
        }
    }

表达式树转SQL(自己实现IQueryable<T>类型)_第1张图片

 

你可能感兴趣的:(表达式树转SQL(自己实现IQueryable类型))