表达式树转SQL(自己实现IQueryable<T>类型)
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<T_Person> GetPerson(string sql)
{
var person = new List<T_Person>();
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>(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>(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<TElement> CreateQuery<TElement>(Expression expression) { Console.WriteLine("建立一个查询,但不执行"); return new MyIQueryable<TElement>(expression, this); } public TResult Execute<TResult>(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<T> : IQueryable<T> { public IEnumerator<T> GetEnumerator() { Console.WriteLine("开始取值"); var result = Provider.Execute<List<T>>(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<T>)); } }
测试代码:
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<T_Person>(); //这里传入什么都没区别,反正里面是硬编码的 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(); } }


浙公网安备 33010602011771号