C# Expression 树转化为SQL语句(一)

   sql有有四中基本语句,分别是增删改查,在建立model后如何生成这四中sql语句,降低开发时间。

   我们先模拟出一张学生表:

 public class Student
        {
            public int id { get; set; }
            public string name { get; set; }
            public int math { get; set; } //数学成绩
            public DateTime createTime { get; set; }
        }

     首先我们来看看增加,也就是插入语句。插入语句语法比较固定变化少通过泛型和反射可以直接生成。string类型和DateTime类型需要加单引号,其他类型不需要加。

  

public static void Main(string[] args)
        {
            Student stu = new Student
            {
                id = 1,
                name = "张三",
                matn = 59,
                createTime = DateTime.Now

            };
            string sql = CreateInsertSql(stu);
            Console.WriteLine(sql);
            Console.ReadLine();
        }
        public static string CreateInsertSql<T>(T model)
        {
            string sql = "Insert into {0}({1}) Values({2})";
            string table = string.Empty;            //表名
            List<string> member = new List<string>(); //全部列名
            List<string> member_value = new List<string>(); //全部的值
            Type type = typeof(T);
            table = type.Name;
            foreach (PropertyInfo item in type.GetProperties())
            {
                string name = item.Name;
                member.Add(name);
                object vaule = item.GetValue(model);
                string v_str = string.Empty;
                if (vaule is string)
                {
                    v_str = string.Format("‘{0}‘", vaule.ToString());
                }
                else if (vaule is DateTime)
                {
                    DateTime time = (DateTime)vaule;
                    v_str = string.Format("‘{0}‘", time.ToString("yyyy-MM-dd HH:mm:ss"));
                }
                else
                {
                    v_str = vaule.ToString();
                }
                member_value.Add(v_str);
            }
            sql = string.Format(sql, table, string.Join(",", member), string.Join(",", member_value));
            return sql;
        }

调试结果为:

  接下来我们来看看其他三种简单sql 删,改,查。简单的分析一下:

删除:前面固定(delete from ) + 表名 + where条件

  修改:前面固定(update) +表名 +set + 修改内容+ where条件

  查找(根据model 我们默认查找全部字段): 前面固定(select * from ) + 表名 +where 条件

  从上面可以看出来我们需要3中参数(表名,修改内容,where条件)表名非常简单,可以把类名作为表名,反射一个就可以得到,接下来就是修改内容和where条件,修改内容比较简单格式为 set  a=a_value,b=b_value .........,where 条件较为复杂。

  用Expression 表达式树是受EntityFrame的启发,有些不了解的可以看看EF的一些函数的定义。

  现在就开始使用Expression表达式树来生产这2种sql语句。

  Expression表达式树有一个基类是Expression,然后有非常都的类继承这个类,我们想获取继承类的名称和命名空间的的时候可以用 :obj.GetType().Name 和obj.getType().Namespace来获取,这样便于调试。

  1. update中的修改内容。假设我们要对学生的分数进行修改(改成60,让人及格),还有姓名(就是凑个字段),其他的数据不修改。

  参数类型为: Expression<Func<Student, Student>> la = n => new Student { name = "李四", matn = 60 }; 我们要生成的sql为 name=‘李四‘,math=60,为什么类型是这个可以去看看EF扩展的内容。

  la类型是LambdaExpression,我们要解析的事la.Body 其类型为MemberInitExpression

 1   public static void Main(string[] args)
 2         {
 3             Expression<Func<Student, Student>> la = n => new Student { name = "李四", matn = 60 };
 4             Console.WriteLine(GetExpressStr((MemberInitExpression)(la.Body)));
 5             Console.ReadLine();
 6         }
 7         public static string GetExpressStr(MemberInitExpression exp)
 8         {
 9             string result = string.Empty;
10             List<string> member = new List<string>();
11             foreach (MemberAssignment item in exp.Bindings)
12             {
13                 string update = item.Member.Name + "=" + GetConstantStr((ConstantExpression)item.Expression);
14                 member.Add(update);
15             }
16             result = string.Join(",", member);
17             return result;
18         }
19         public static string GetConstantStr(ConstantExpression exp)
20         {
21             object vaule = exp.Value;
22             string v_str = string.Empty;
23             if (vaule is string)
24             {
25                 v_str = string.Format("‘{0}‘", vaule.ToString());
26             }
27             else if (vaule is DateTime)
28             {
29                 DateTime time = (DateTime)vaule;
30                 v_str = string.Format("‘{0}‘", time.ToString("yyyy-MM-dd HH:mm:ss"));
31             }
32             else
33             {
34                 v_str = vaule.ToString();
35             }
36             return v_str;
37         }

调试结果:

  2.where条件

  where条件是最麻烦的地方。之前的只有等于号,而where却有大于,小于,且或等等符号,不过Exresion基类中提供了NodeType 类型为ExpressionType,我们可以获取到对应的运算符。参数类型为

  Expression<Func<Student,bool>>   简单理解where条件是每条数据符合不符合,所以返回值为bool
  1 public static void Main(string[] args)
  2         {
  3             Expression<Func<Student,bool>> la =( n=>n.id > 1 && n.id <100 &&n.name !="张三" && n.matn >=60 && n.id != 50 && n.createTime != null);
  4             Console.WriteLine(DealExpress(la));
  5             Console.ReadLine();
  6         }
  7         public static string DealExpress(Expression exp)
  8         {
  9             if (exp is LambdaExpression )
 10             {
 11                 LambdaExpression l_exp = exp as LambdaExpression;
 12                 return   DealExpress(l_exp.Body);
 13             }
 14             if (exp is BinaryExpression)
 15             {
 16                 return DealBinaryExpression(exp as BinaryExpression);
 17             }
 18             if (exp is MemberExpression)
 19             {
 20                 return DealMemberExpression(exp as MemberExpression);
 21             }
 22             if (exp is ConstantExpression)
 23             {
 24                 return DealConstantExpression(exp as ConstantExpression);
 25             }
 26             if (exp is UnaryExpression)
 27             {
 28                 return DealUnaryExpression(exp as UnaryExpression);
 29             }
 30             return "";
 31         }
 32         public static string DealUnaryExpression(UnaryExpression exp)
 33         {
 34             return DealExpress(exp.Operand);
 35         }
 36         public static string DealConstantExpression(ConstantExpression exp)
 37         {
 38             object vaule = exp.Value;
 39             string v_str = string.Empty;
 40             if (vaule == null)
 41             {
 42                 return "NULL";
 43             }
 44             if (vaule is string)
 45             {
 46                 v_str = string.Format("‘{0}‘", vaule.ToString());
 47             }
 48             else if (vaule is DateTime)
 49             {
 50                 DateTime time = (DateTime)vaule;
 51                 v_str = string.Format("‘{0}‘", time.ToString("yyyy-MM-dd HH:mm:ss"));
 52             }
 53             else
 54             {
 55                 v_str = vaule.ToString();
 56             }
 57             return v_str;
 58         }
 59         public static string DealBinaryExpression(BinaryExpression exp)
 60         {
 61
 62             string left = DealExpress(exp.Left);
 63             string oper = GetOperStr(exp.NodeType);
 64             string right = DealExpress(exp.Right);
 65             if (right == "NULL")
 66             {
 67                 if (oper == "=")
 68                 {
 69                     oper = " is ";
 70                 }
 71                 else
 72                 {
 73                     oper = " is not ";
 74                 }
 75             }
 76             return left + oper + right;
 77         }
 78         public static string DealMemberExpression(MemberExpression exp)
 79         {
 80              return exp.Member.Name;
 81         }
 82         public static string GetOperStr(ExpressionType e_type)
 83         {
 84             switch (e_type)
 85             {
 86                 case ExpressionType.OrElse: return " OR ";
 87                 case ExpressionType.Or: return "|";
 88                 case ExpressionType.AndAlso: return " AND ";
 89                 case ExpressionType.And: return "&";
 90                 case ExpressionType.GreaterThan: return ">";
 91                 case ExpressionType.GreaterThanOrEqual: return ">=";
 92                 case ExpressionType.LessThan: return "<";
 93                 case ExpressionType.LessThanOrEqual: return "<=";
 94                 case ExpressionType.NotEqual: return "<>";
 95                 case ExpressionType.Add: return "+";
 96                 case ExpressionType.Subtract: return "-";
 97                 case ExpressionType.Multiply: return "*";
 98                 case ExpressionType.Divide: return "/";
 99                 case ExpressionType.Modulo: return "%";
100                 case ExpressionType.Equal: return "=";
101             }
102             return "";
103         }

调试结果:

这些代码中一些漏洞,仅供大家参考学习,这些代码目前不能接受参数,如n=>n.id==m(int m=1),下一篇将会对Expression表达式树的参数进行解析,欢迎大家指正。

时间: 2024-10-13 10:47:51

C# Expression 树转化为SQL语句(一)的相关文章

C#实现把String字符串转化为SQL语句中的In后接的参数

实现把String字符串转化为In后可用参数代码: public string StringToList(string aa) { string bb1 = "("; if (!string.IsNullOrEmpty(aa.Trim())) { string[] bb = aa.Split(new string[] { "\r\n", ",", ";", "* " }, StringSplitOption

EF中执行sql语句

EF原理 EF 会自动把 Where().OrderBy().Select()等这些编译成"表达式树(Expression Tree)",然后会把表达式树翻译成 SQL 语句去执行.(编译原理,AST)因此不是"把数据都取到内存中,然后使用集合的方法进行数据过滤",因此性能不会低.但是如果这个操作不能被翻译成 SQL 语句,则或者报错,或者被放到内存中操作,性能就会非常低 跟踪EF的查询Sql语句: DbContext 有一个 Database 属性,其中的 Log

数据库-转换sql语句

文章描述:主要说明转换成SQL语句的过程.----必要信息(数据库名,表名,条件)转换成SQL语句 一些界面上数据增删改查的操作往往只需要输入一数据库名,表名,加条件就可以进行数据查询了,在这背后是怎么实现了呢,这些程序有些是使用封装的方法,有些直接输入sql语句进行操作,封装的方法最后也是将查询条件(上面输入操作)转换为SQL语句用Statement对象对应方法进行相关操作 而Statement对象获得SQL语句后怎么执行查询(这个不归statement管了),Statement这里是通过jd

SQL语句中使用 with 递归实现表中数据树状显示

在开发过程中会遇到很多实现树状的功能,之前为了实现数据的树状显示一般都是通过程序里面的递归实现,今天试了一下通过sql语句实现具体如下: 表名:DeptInfo 字段:DeptId(部门编号),DeptName(部门名称),DeptUpId(部门上级ID),DeptPath(部门层级) 从DeptUpId和DeptPath中可看出表数据可能很乱: 为了实现表中数据树状显示,条例清晰具体代码实现如下: with dept as(select DeptId,DeptUpId from DeptInf

Expression 转化为sql(三) --自定义函数

SQL 语句有很多函数如len(),now()等等.如何来生成这些函数.最近研究也写办法共大家参考. 一.首先建立一个建一个扩展类,控制只能允许这些函数出现,如果出现其他函数就直接报异常. 1 public static class SQLMethods 2 { 3 public static bool DB_In<T>(this T t, List<T> list) // in 4 { 5 return true; 6 } 7 public static Boolean DB_N

LINQ to SQL语句入门篇 纯属转载

Where操作 适用场景:实现过滤,查询等功能. 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的子句. Where操作包括3种形式,分别为简单形式.关系条件形式.First()形式.下面分别用实例举例下: 1.简单形式: 例如:使用where筛选在伦敦的客户 var q = from c in db.Customers where c.City == "London" select c; 再如:筛选1994 年或之后雇用的雇员:

LINQ to SQL语句(1)之Where(抄的好)

Where操作 适用场景:实现过滤,查询等功能. 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的子句. Where操作包括3种形式,分别为简单形式.关系条件形式.First()形式.下面分别用实例举例下: 1.简单形式: 例如:使用where筛选在伦敦的客户 var q = from c in db.Customers where c.City == "London" select c; 再如:筛选1994 年或之后雇用的雇员:

LINQ to SQL语句非常详细(原文来自于网络)

LINQ to SQL语句(1)之Where Where操作 适用场景:实现过滤,查询等功能. 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的子句. Where操作包括3种形式,分别为简单形式.关系条件形式.First()形式.下面分别用实例举例下: 1.简单形式: 例如:使用where筛选在伦敦的客户 var q = from c in db.Customers where c.City == "London" select c

转:sql语句优化

性能不理想的系统中除了一部分是因为应用程序的负载确实超过了服务器的实际处理能力外,更多的是因为系统存在大量的SQL语句需要优化. 为了获得稳定的执行性能,SQL语句越简单越好.对复杂的SQL语句,要设法对之进行简化. 常见的简化规则如下: 1)不要有超过5个以上的表连接(JOIN)2)考虑使用临时表或表变量存放中间结果.3)少用子查询4)视图嵌套不要过深,一般视图嵌套不要超过2个为宜. 连接的表越多,其编译的时间和连接的开销也越大,性能越不好控制. 最好是把连接拆开成较小的几个部分逐个顺序执行.