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 = , /// <summary>
/// 一元运算符
/// </summary>
[Description("一元运算符")]
UndryOperator = , /// <summary>
/// 常量表达式
/// </summary>
[Description("常量表达式")]
Constant = , /// <summary>
/// 成员(变量)
/// </summary>
[Description("成员(变量)")]
MemberAccess = , /// <summary>
/// 函数
/// </summary>
[Description("函数")]
Call = , /// <summary>
/// 未知
/// </summary>
[Description("未知")]
Unknown = -, /// <summary>
/// 不支持
/// </summary>
[Description("不支持")]
NotSupported = -
} /// <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(, sb.Length - ) + " is null";
else if (sb.EndsWith(" <> "))
sb = sb.Substring(, sb.Length - ) + " 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(, sbTmp.ToString().Length - );
}
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(, sbTmp.ToString().Length - );
}
}
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[], listSqlParaModel), ExpressionRouter(mce.Arguments[], listSqlParaModel));
}
else
{
if (mce.Object.NodeType == ExpressionType.MemberAccess)
{
//w => w.name.Contains("1")
var _name = ExpressionRouter(mce.Object, listSqlParaModel);
var _value = ExpressionRouter(mce.Arguments[], listSqlParaModel);
var index = _value.RetainNumber().ToInt32() - ;
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[], listSqlParaModel));
}
else if (mce.Method.Name == "OrderByDescending")
{
return string.Format("{0} desc", ExpressionRouter(mce.Arguments[], listSqlParaModel));
}
else if (mce.Method.Name == "ThenBy")
{
return string.Format("{0},{1} asc", MethodCallExpressionProvider(mce.Arguments[], listSqlParaModel), ExpressionRouter(mce.Arguments[], listSqlParaModel));
}
else if (mce.Method.Name == "ThenByDescending")
{
return string.Format("{0},{1} desc", MethodCallExpressionProvider(mce.Arguments[], listSqlParaModel), ExpressionRouter(mce.Arguments[], listSqlParaModel));
}
else if (mce.Method.Name == "Like")
{
return string.Format("({0} like {1})", ExpressionRouter(mce.Arguments[], listSqlParaModel), ExpressionRouter(mce.Arguments[], listSqlParaModel).Replace("'", ""));
}
else if (mce.Method.Name == "NotLike")
{
return string.Format("({0} not like '%{1}%')", ExpressionRouter(mce.Arguments[], listSqlParaModel), ExpressionRouter(mce.Arguments[], listSqlParaModel).Replace("'", ""));
}
else if (mce.Method.Name == "In")
{
return string.Format("{0} in ({1})", ExpressionRouter(mce.Arguments[], listSqlParaModel), ExpressionRouter(mce.Arguments[], listSqlParaModel));
}
else if (mce.Method.Name == "NotIn")
{
return string.Format("{0} not in ({1})", ExpressionRouter(mce.Arguments[], listSqlParaModel), ExpressionRouter(mce.Arguments[], 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(, sbTmp.Length - );
} 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 + );
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 = ; 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 > )
{
sbSelectFields = sbSelectFields.Remove(sbSelectFields.Length - , );
}
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("");
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;
}

lambda表达式转换sql的更多相关文章

  1. Lambda表达式转SQL语句类库

    /* 作者:道法自然   * 个人邮件:myyangbin@sina.cn * 2014-10-1 */ Lambda表达式转SQL语句类库源码下载:http://download.csdn.net/ ...

  2. C#中的Lambda表达式和表达式树

    在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化.但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响.C# 3.0中出现的Lambda表达式在 ...

  3. 《C#本质论》读书笔记(12)委托和Lambda表达式

    12.1.委托概述 12.1.2 委托的数据类型 为了减少重复代码数量,可以将比较方法作为参数传递给 BubbleSort()方法.此外,为了将方法作为参数传递,必须有一个能够标识方法的数据类型--也 ...

  4. Lambda表达式和表达式树

    在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化.但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响.C# 3.0中出现的Lambda表达式在 ...

  5. 转:【More Effective C#】Lambda表达式优化

    http://www.cnblogs.com/kongyiyun/archive/2010/10/19/1855274.html 使用Lambda表达式将会造成Lambda表达式主题部分的代码重复. ...

  6. Lambda表达式和Lambda表达式树

    LINQ的基本功能就是创建操作管道,以及这些操作需要的任何状态. 为了富有效率的使用数据库和其他查询引擎,我们需要一种不同的方式表示管道中的各个操作.即把代码当作可在编程中进行检查的数据. Lambd ...

  7. lambda函数、lambda表达式

    C++11 新特性:Lambda 表达式 豆子 2012年5月15日 C++ 10条评论 参考文章:https://blogs.oracle.com/pcarlini/entry/c_1x_tidbi ...

  8. C#在泛型类中,通过表达式树构造lambda表达式

    场景 最近对爬虫的数据库架构做调整,需要将数据迁移到MongoDB上去,需要重新实现一个针对MongoDB的Dao泛型类,好吧,动手开工,当实现删除操作的时候问题来了. 我们的删除操作定义如下:voi ...

  9. C#中的委托,匿名方法和Lambda表达式

    简介 在.NET中,委托,匿名方法和Lambda表达式很容易发生混淆.我想下面的代码能证实这点.下面哪一个First会被编译?哪一个会返回我们需要的结果?即Customer.ID=.答案是6个Firs ...

随机推荐

  1. gcc编译生成静态及动态链接库步骤

    gcc编译生成静态及动态链接库步骤 这两天在看<Linux C程序设计大全>,吴岳编著,清华大学出版社.这本书是在一个培训机构看到的,在网上查了下该书的相关信息.从目录而言,该书涵盖了Li ...

  2. leetcode 389 map iterator 的使用

    class Solution { public: char findTheDifference(string s, string t) { map<char,int>Map_Temp; ; ...

  3. Origin 2018 的坐标轴中文标签发生倒立/翻转

    问题: 在使用 origin 2018 作图时,坐标轴或者是标签中输入中文后,将其更换中文字体(英文字体没有该问题)后发生倒立的情况 解决: 后来发现 Origin 2018 中存在两种中文字体,其中 ...

  4. linux把时间类型值转换为数值型

    字符及字符串处理函数:字符及字符串处理函数的处理对象均为字符型数据,但其返回值类型各异.1.取子串函数:格式:substr(c,n1,n2)功能:取字符串C第n1个字符起的n2个字符.返回值类型是字符 ...

  5. NOIP2015提高组T2 洛谷P2661 信息传递

    题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...

  6. 【BZOJ4542】大数(莫队)

    题意:给定一个N位的由[0..9]组成的数字串和质数P,有M次不强制在线的询问,每次询问区间[l,r]中模P意义下为0的子串个数 N,M<=2e5,P<=1e10 思路:一次A,本来还以为 ...

  7. 张孝祥JavaScript视频教程flash版

    原文发布时间为:2008-09-16 -- 来源于本人的百度文章 [由搬家工具导入] 之前论坛有人发过RM版的,容量差不多有10G.现在这个是flash版的,只有1.2G共七部分. 第一部分:http ...

  8. AJAX在VS2005中的简单应用 使用ajaxpro.2.dll[点击按钮执行事件不刷新]

    原文发布时间为:2008-10-21 -- 来源于本人的百度文章 [由搬家工具导入] 1.下載ajaxpro.dll或AjaxPro.2.dll 放在Bin文件夹中2.配置web.config 3.u ...

  9. web.config add handlers and httpmodule to System.Web section.

    <?xml version="1.0" encoding="utf-8"?> <!-- For more information on how ...

  10. Docker(八):私有仓库

    有时候使用Docker Hub这样的公共仓库可能不太方便,用户可以创建一个本地仓库供私人使用. 在安装了Docker之后,可以获取官方的registry镜像来运行,docker-registry是官方 ...