zoukankan      html  css  js  c++  java
  • lambda表达式转换sql

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace MaiCore
    {
        /// <summary>
        /// 
        /// </summary>
        public class LambdaToSqlHelper
        {
            /// <summary>
            /// NodeType枚举
            /// </summary>
            private enum EnumNodeType
            {
                /// <summary>
                /// 二元运算符
                /// </summary>
                [Description("二元运算符")]
                BinaryOperator = 1,
    
                /// <summary>
                /// 一元运算符
                /// </summary>
                [Description("一元运算符")]
                UndryOperator = 2,
    
                /// <summary>
                /// 常量表达式
                /// </summary>
                [Description("常量表达式")]
                Constant = 3,
    
                /// <summary>
                /// 成员(变量)
                /// </summary>
                [Description("成员(变量)")]
                MemberAccess = 4,
    
                /// <summary>
                /// 函数
                /// </summary>
                [Description("函数")]
                Call = 5,
    
                /// <summary>
                /// 未知
                /// </summary>
                [Description("未知")]
                Unknown = -99,
    
                /// <summary>
                /// 不支持
                /// </summary>
                [Description("不支持")]
                NotSupported = -98
            }
    
            /// <summary>
            /// 判断表达式类型
            /// </summary>
            /// <param name="exp">lambda表达式</param>
            /// <returns></returns>
            private static EnumNodeType CheckExpressionType(Expression exp)
            {
                switch (exp.NodeType)
                {
                    case ExpressionType.AndAlso:
                    case ExpressionType.OrElse:
                    case ExpressionType.Equal:
                    case ExpressionType.GreaterThanOrEqual:
                    case ExpressionType.LessThanOrEqual:
                    case ExpressionType.GreaterThan:
                    case ExpressionType.LessThan:
                    case ExpressionType.NotEqual:
                        return EnumNodeType.BinaryOperator;
                    case ExpressionType.Constant:
                        return EnumNodeType.Constant;
                    case ExpressionType.MemberAccess:
                        return EnumNodeType.MemberAccess;
                    case ExpressionType.Call:
                        return EnumNodeType.Call;
                    case ExpressionType.Not:
                    case ExpressionType.Convert:
                        return EnumNodeType.UndryOperator;
                    default:
                        return EnumNodeType.Unknown;
                }
            }
    
            /// <summary>
            /// 表达式类型转换
            /// </summary>
            /// <param name="type"></param>
            /// <returns></returns>
            private static string ExpressionTypeCast(ExpressionType type)
            {
                switch (type)
                {
                    case ExpressionType.And:
                    case ExpressionType.AndAlso:
                        return " and ";
                    case ExpressionType.Equal:
                        return " = ";
                    case ExpressionType.GreaterThan:
                        return " > ";
                    case ExpressionType.GreaterThanOrEqual:
                        return " >= ";
                    case ExpressionType.LessThan:
                        return " < ";
                    case ExpressionType.LessThanOrEqual:
                        return " <= ";
                    case ExpressionType.NotEqual:
                        return " <> ";
                    case ExpressionType.Or:
                    case ExpressionType.OrElse:
                        return " or ";
                    case ExpressionType.Add:
                    case ExpressionType.AddChecked:
                        return " + ";
                    case ExpressionType.Subtract:
                    case ExpressionType.SubtractChecked:
                        return " - ";
                    case ExpressionType.Divide:
                        return " / ";
                    case ExpressionType.Multiply:
                    case ExpressionType.MultiplyChecked:
                        return " * ";
                    default:
                        return null;
                }
            }
    
            private static string BinarExpressionProvider(Expression exp, List<SqlParaModel> listSqlParaModel)
            {
                BinaryExpression be = exp as BinaryExpression;
                Expression left = be.Left;
                Expression right = be.Right;
                ExpressionType type = be.NodeType;
                string sb = "(";
                //先处理左边
                sb += ExpressionRouter(left, listSqlParaModel);
                sb += ExpressionTypeCast(type);
                //再处理右边
                string sbTmp = ExpressionRouter(right, listSqlParaModel);
                if (sbTmp == "null")
                {
                    if (sb.EndsWith(" = "))
                        sb = sb.Substring(0, sb.Length - 2) + " is null";
                    else if (sb.EndsWith(" <> "))
                        sb = sb.Substring(0, sb.Length - 2) + " is not null";
                }
                else
                    sb += sbTmp;
                return sb += ")";
            }
    
            private static string ConstantExpressionProvider(Expression exp, List<SqlParaModel> listSqlParaModel)
            {
                ConstantExpression ce = exp as ConstantExpression;
                if (ce.Value == null)
                {
                    return "null";
                }
                else if (ce.Value is ValueType)
                {
                    GetSqlParaModel(listSqlParaModel, GetValueType(ce.Value));
                    return "@para" + listSqlParaModel.Count;
                }
                else if (ce.Value is string || ce.Value is DateTime || ce.Value is char)
                {
                    GetSqlParaModel(listSqlParaModel, GetValueType(ce.Value));
                    return "@para" + listSqlParaModel.Count;
                }
                return "";
            }
    
            private static string LambdaExpressionProvider(Expression exp, List<SqlParaModel> listSqlParaModel)
            {
                LambdaExpression le = exp as LambdaExpression;
                return ExpressionRouter(le.Body, listSqlParaModel);
            }
    
            private static string MemberExpressionProvider(Expression exp, List<SqlParaModel> listSqlParaModel)
            {
                if (!exp.ToString().StartsWith("value"))
                {
                    MemberExpression me = exp as MemberExpression;
                    if (me.Member.Name == "Now")
                    {
                        GetSqlParaModel(listSqlParaModel, DateTime.Now);
                        return "@para" + listSqlParaModel.Count;
                    }
                    return me.Member.Name;
                }
                else
                {
                    var result = Expression.Lambda(exp).Compile().DynamicInvoke();
                    if (result == null)
                    {
                        return "null";
                    }
                    else if (result is ValueType)
                    {
                        GetSqlParaModel(listSqlParaModel, GetValueType(result));
                        return "@para" + listSqlParaModel.Count;
                    }
                    else if (result is string || result is DateTime || result is char)
                    {
                        GetSqlParaModel(listSqlParaModel, GetValueType(result));
                        return "@para" + listSqlParaModel.Count;
                    }
                    else if (result is int[])
                    {
                        var rl = result as int[];
                        StringBuilder sbTmp = new StringBuilder();
                        foreach (var r in rl)
                        {
                            GetSqlParaModel(listSqlParaModel, r.ToString().ToInt32());
                            sbTmp.Append("@para" + listSqlParaModel.Count + ",");
                        }
                        return sbTmp.ToString().Substring(0, sbTmp.ToString().Length - 1);
                    }
                    else if (result is string[])
                    {
                        var rl = result as string[];
                        StringBuilder sbTmp = new StringBuilder();
                        foreach (var r in rl)
                        {
                            GetSqlParaModel(listSqlParaModel, r.ToString());
                            sbTmp.Append("@para" + listSqlParaModel.Count + ",");
                        }
                        return sbTmp.ToString().Substring(0, sbTmp.ToString().Length - 1);
                    }                
                }
                return "";
            }
    
            private static string MethodCallExpressionProvider(Expression exp, List<SqlParaModel> listSqlParaModel)
            {
                MethodCallExpression mce = exp as MethodCallExpression;
                if (mce.Method.Name == "Contains")
                {
                    if (mce.Object == null)
                    {
                        return string.Format("{0} in ({1})", ExpressionRouter(mce.Arguments[1], listSqlParaModel), ExpressionRouter(mce.Arguments[0], listSqlParaModel));
                    }
                    else
                    {
                        if (mce.Object.NodeType == ExpressionType.MemberAccess)
                        {
                            //w => w.name.Contains("1")
                            var _name = ExpressionRouter(mce.Object, listSqlParaModel);
                            var _value = ExpressionRouter(mce.Arguments[0], listSqlParaModel);
                            var index = _value.RetainNumber().ToInt32() - 1;
                            listSqlParaModel[index].value = "%{0}%".FormatWith(listSqlParaModel[index].value);
                            return string.Format("{0} like {1}", _name, _value);
                        }
                    }
                }
                else if (mce.Method.Name == "OrderBy")
                {
                    return string.Format("{0} asc", ExpressionRouter(mce.Arguments[1], listSqlParaModel));
                }
                else if (mce.Method.Name == "OrderByDescending")
                {
                    return string.Format("{0} desc", ExpressionRouter(mce.Arguments[1], listSqlParaModel));
                }
                else if (mce.Method.Name == "ThenBy")
                {
                    return string.Format("{0},{1} asc", MethodCallExpressionProvider(mce.Arguments[0], listSqlParaModel), ExpressionRouter(mce.Arguments[1], listSqlParaModel));
                }
                else if (mce.Method.Name == "ThenByDescending")
                {
                    return string.Format("{0},{1} desc", MethodCallExpressionProvider(mce.Arguments[0], listSqlParaModel), ExpressionRouter(mce.Arguments[1], listSqlParaModel));
                }
                else if (mce.Method.Name == "Like")
                {
                    return string.Format("({0} like {1})", ExpressionRouter(mce.Arguments[0], listSqlParaModel), ExpressionRouter(mce.Arguments[1], listSqlParaModel).Replace("'", ""));
                }
                else if (mce.Method.Name == "NotLike")
                {
                    return string.Format("({0} not like '%{1}%')", ExpressionRouter(mce.Arguments[0], listSqlParaModel), ExpressionRouter(mce.Arguments[1], listSqlParaModel).Replace("'", ""));
                }
                else if (mce.Method.Name == "In")
                {
                    return string.Format("{0} in ({1})", ExpressionRouter(mce.Arguments[0], listSqlParaModel), ExpressionRouter(mce.Arguments[1], listSqlParaModel));
                }
                else if (mce.Method.Name == "NotIn")
                {
                    return string.Format("{0} not in ({1})", ExpressionRouter(mce.Arguments[0], listSqlParaModel), ExpressionRouter(mce.Arguments[1], listSqlParaModel));
                }
                return "";
            }
    
            private static string NewArrayExpressionProvider(Expression exp, List<SqlParaModel> listSqlParaModel)
            {
                NewArrayExpression ae = exp as NewArrayExpression;
                StringBuilder sbTmp = new StringBuilder();
                foreach (Expression ex in ae.Expressions)
                {
                    sbTmp.Append(ExpressionRouter(ex, listSqlParaModel));
                    sbTmp.Append(",");
                }
                return sbTmp.ToString(0, sbTmp.Length - 1);
            }
    
            private static string ParameterExpressionProvider(Expression exp, List<SqlParaModel> listSqlParaModel)
            {
                ParameterExpression pe = exp as ParameterExpression;
                return pe.Type.Name;
            }
    
            private static string UnaryExpressionProvider(Expression exp, List<SqlParaModel> listSqlParaModel)
            {
                UnaryExpression ue = exp as UnaryExpression;
                var result = ExpressionRouter(ue.Operand, listSqlParaModel);
                ExpressionType type = exp.NodeType;
                if (type == ExpressionType.Not)
                {
                    if (result.Contains(" in "))
                    {
                        result = result.Replace(" in ", " not in ");
                    }
                    if (result.Contains(" like "))
                    {
                        result = result.Replace(" like ", " not like ");
                    }
                }
                return result;
            }
    
            /// <summary>
            /// 路由计算
            /// </summary>
            /// <param name="exp"></param>
            /// <param name="listSqlParaModel"></param>
            /// <returns></returns>
            private static string ExpressionRouter(Expression exp, List<SqlParaModel> listSqlParaModel)
            {
                var nodeType = exp.NodeType;
                if (exp is BinaryExpression)    //表示具有二进制运算符的表达式
                {
                    return BinarExpressionProvider(exp, listSqlParaModel);
                }
                else if (exp is ConstantExpression) //表示具有常数值的表达式
                {
                    return ConstantExpressionProvider(exp, listSqlParaModel);
                }
                else if (exp is LambdaExpression)   //介绍 lambda 表达式。 它捕获一个类似于 .NET 方法主体的代码块
                {
                    return LambdaExpressionProvider(exp, listSqlParaModel);
                }
                else if (exp is MemberExpression)   //表示访问字段或属性
                {
                    return MemberExpressionProvider(exp, listSqlParaModel);
                }
                else if (exp is MethodCallExpression)   //表示对静态方法或实例方法的调用
                {
                    return MethodCallExpressionProvider(exp, listSqlParaModel);
                }
                else if (exp is NewArrayExpression) //表示创建一个新数组,并可能初始化该新数组的元素
                {
                    return NewArrayExpressionProvider(exp, listSqlParaModel);
                }
                else if (exp is ParameterExpression)    //表示一个命名的参数表达式。
                {
                    return ParameterExpressionProvider(exp, listSqlParaModel);
                }
                else if (exp is UnaryExpression)    //表示具有一元运算符的表达式
                {
                    return UnaryExpressionProvider(exp, listSqlParaModel);
                }
                return null;
            }
    
            /// <summary>
            /// 值类型转换
            /// </summary>
            /// <param name="_value"></param>
            /// <returns></returns>
            private static object GetValueType(object _value)
            {
                var _type = _value.GetType().Name;
                switch (_type)
                {
                    case "Decimal ": return _value.ToDecimal();
                    case "Int32": return _value.ToInt32();
                    case "DateTime": return _value.ToDateTime();
                    case "String": return _value.ToString();
                    case "Char":return _value.ToChar();
                    case "Boolean":return _value.ToBoolean();
                    default: return _value;
                }
            }
    
            /// <summary>
            /// sql参数
            /// </summary>
            /// <param name="listSqlParaModel"></param>
            /// <param name="val"></param>
            private static void GetSqlParaModel(List<SqlParaModel> listSqlParaModel, object val)
            {
                SqlParaModel p = new SqlParaModel();
                p.name = "para" + (listSqlParaModel.Count + 1);
                p.value = val;
                listSqlParaModel.Add(p);
            }
    
            /// <summary>
            /// lambda表达式转换sql
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="where"></param>
            /// <param name="listSqlParaModel"></param>
            /// <returns></returns>
            public static string GetWhereSql<T>(Expression<Func<T, bool>> where, List<SqlParaModel> listSqlParaModel) where T : class
            {
                string result = string.Empty;
                if (where != null)
                {
                    Expression exp = where.Body as Expression;
                    result = ExpressionRouter(exp, listSqlParaModel);
                }
                if (result != string.Empty)
                {
                    result = " where " + result;
                }
                return result;
            }
    
            /// <summary>
            /// lambda表达式转换sql
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="orderBy"></param>
            /// <returns></returns>
            public static string GetOrderBySql<T>(Expression<Func<IQueryable<T>, IOrderedQueryable<T>>> orderBy) where T : class
            {
                string result = string.Empty;
                if (orderBy != null && orderBy.Body is MethodCallExpression)
                {
                    MethodCallExpression exp = orderBy.Body as MethodCallExpression;
                    List<SqlParaModel> listSqlParaModel = new List<SqlParaModel>();
                    result = MethodCallExpressionProvider(exp, listSqlParaModel);
                }
                if (result != string.Empty)
                {
                    result = " order by " + result;
                }
                return result;
            }
    
            /// <summary>
            /// lambda表达式转换sql
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="fields"></param>
            /// <returns></returns>
            public static string GetQueryField<T>(Expression<Func<T, object>> fields)
            {
                StringBuilder sbSelectFields = new StringBuilder();
                if (fields.Body is NewExpression)
                {
                    NewExpression ne = fields.Body as NewExpression;
                    for (var i = 0; i < ne.Members.Count; i++)
                    {
                        sbSelectFields.Append(ne.Members[i].Name + ",");
                    }
                }
                else if (fields.Body is ParameterExpression)
                {
                    sbSelectFields.Append("*");
                }
                else
                {
                    sbSelectFields.Append("*");
                }
                if (sbSelectFields.Length > 1)
                {
                    sbSelectFields = sbSelectFields.Remove(sbSelectFields.Length - 1, 1);
                }
                return sbSelectFields.ToString();
            }
    
        }
    }
    
     
    
    -----------------------------------------------------------------------------------------------
    
    demo:
    
        class Program
        {
    
            static void Main(string[] args)
            {
                //Expression<Func<MyClass, bool>> where = w => w.id == "123456";
                Expression<Func<MyClass, bool>> where = w => w.id.Contains("1");
                List<SqlParaModel> listSqlParaModel = new List<SqlParaModel>();
                var sql = LambdaToSqlHelper.GetWhereSql(where, listSqlParaModel);
            }
    
        }
    
        class MyClass
        {
            public string id;
            public string name;
            public string desc;
            public decimal price;
            public int stock;
            public bool isShow;
            public DateTime createTime;
        }
    
     
  • 相关阅读:
    Cgroup学习笔记
    基于dubbo框架下的RPC通讯协议性能测试
    More about dubbo
    基于nginx tomcat redis分布式web应用的session共享配置
    基于开源Dubbo分布式RPC服务框架的部署整合
    More about Tair (NoSql)
    MySql Replication配置
    Memcached、Redis OR Tair
    基于淘宝开源Tair分布式KV存储引擎的整合部署
    关于TbSchedule任务调度管理框架的整合部署
  • 原文地址:https://www.cnblogs.com/zzp0320/p/7154895.html
Copyright © 2011-2022 走看看