• 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

    public static void Main(string[] args)
    {
    Expression<Func<Student, Student>> la = n => new Student { name = "李四", matn = 60 };
    Console.WriteLine(GetExpressStr((MemberInitExpression)(la.Body)));
    Console.ReadLine();
    }
    public static string GetExpressStr(MemberInitExpression exp)
    {
    string result = string.Empty;
    List<string> member = new List<string>();
    foreach (MemberAssignment item in exp.Bindings)
    {
    string update = item.Member.Name + "=" + GetConstantStr((ConstantExpression)item.Expression);
    member.Add(update);
    }
    result = string.Join(",", member);
    return result;
    }
    public static string GetConstantStr(ConstantExpression exp)
    {
    object vaule = exp.Value;
    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();
    }
    return v_str;
    }

    调试结果:

      2.where条件

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

     Expression<Func<Student,bool>>   简单理解where条件是每条数据符合不符合,所以返回值为bool

    public static void Main(string[] args)
    {
    Expression<Func<Student,bool>> la =( n=>n.id > 1 && n.id <100 &&n.name !="张三" && n.matn >=60 && n.id != 50 && n.createTime != null);
    Console.WriteLine(DealExpress(la));
    Console.ReadLine();
    }
    public static string DealExpress(Expression exp)
    {
    if (exp is LambdaExpression )
    {
    LambdaExpression l_exp = exp as LambdaExpression;
    return DealExpress(l_exp.Body);
    }
    if (exp is BinaryExpression)
    {
    return DealBinaryExpression(exp as BinaryExpression);
    }
    if (exp is MemberExpression)
    {
    return DealMemberExpression(exp as MemberExpression);
    }
    if (exp is ConstantExpression)
    {
    return DealConstantExpression(exp as ConstantExpression);
    }
    if (exp is UnaryExpression)
    {
    return DealUnaryExpression(exp as UnaryExpression);
    }
    return "";
    }
    public static string DealUnaryExpression(UnaryExpression exp)
    {
    return DealExpress(exp.Operand);
    }
    public static string DealConstantExpression(ConstantExpression exp)
    {
    object vaule = exp.Value;
    string v_str = string.Empty;
    if (vaule == null)
    {
    return "NULL";
    }
    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();
    }
    return v_str;
    }
    public static string DealBinaryExpression(BinaryExpression exp)
    {

    string left = DealExpress(exp.Left);
    string oper = GetOperStr(exp.NodeType);
    string right = DealExpress(exp.Right);
    if (right == "NULL")
    {
    if (oper == "=")
    {
    oper = " is ";
    }
    else
    {
    oper = " is not ";
    }
    }
    return left + oper + right;
    }
    public static string DealMemberExpression(MemberExpression exp)
    {
    return exp.Member.Name;
    }
    public static string GetOperStr(ExpressionType e_type)
    {
    switch (e_type)
    {
    case ExpressionType.OrElse: return " OR ";
    case ExpressionType.Or: return "|";
    case ExpressionType.AndAlso: return " AND ";
    case ExpressionType.And: return "&";
    case ExpressionType.GreaterThan: return ">";
    case ExpressionType.GreaterThanOrEqual: return ">=";
    case ExpressionType.LessThan: return "<";
    case ExpressionType.LessThanOrEqual: return "<=";
    case ExpressionType.NotEqual: return "<>";
    case ExpressionType.Add: return "+";
    case ExpressionType.Subtract: return "-";
    case ExpressionType.Multiply: return "*";
    case ExpressionType.Divide: return "/";
    case ExpressionType.Modulo: return "%";
    case ExpressionType.Equal: return "=";
    }
    return "";
    }

    调试结果:

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

    http://www.cnblogs.com/linxingxunyan/p/6245396.html

  • 相关阅读:
    年终总结 2016-08-28 22:04 422人阅读 评论(26) 收藏
    [mysql]MySQL Daemon failed to start 2016-08-14 21:27 1121人阅读 评论(18) 收藏
    solrr初步了解 2016-07-31 22:29 380人阅读 评论(4) 收藏
    基于spring-boot的测试桩设计--几种常见的controller
    利用Factory-boy和sqlalchemy来批量生成数据库表数据
    job中shell脚本异常(删除不存在容器),导致job被打断执行的问题 脚本优化方法
    利用Factory-boy来生成实例数据
    pytest相关资源收集
    pytest 用 @pytest.mark.usefixtures("fixtureName")装饰类,可以让执行每个case前,都执行一遍指定的fixture
    pytest fixture 利用 params参数实现用例集合
  • 原文地址:https://www.cnblogs.com/sjqq/p/8428757.html
Copyright © 2020-2023  润新知