玩转NET Expression
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Fast.Framework.Models; namespace Fast.Framework.Extensions
{ /// <summary>
/// 表达式扩展类
/// </summary>
public static class ExpressionExtensions
{
/// <summary>
/// 解析Sql
/// </summary>
/// <param name="expression">表达式</param>
/// <param name="options">选项</param>
/// <returns></returns>
public static SqlInfo ResolveSql(this Expression expression, SqlExpressionOptions options)
{
var ex = new SqlExpressionVisitor(options);
ex.Visit(expression);
return ex.sqlInfo;
}
} /// <summary>
/// 解析类型
/// </summary>
public enum ResolveType
{
/// <summary>
/// Sql字符串
/// </summary>
SqlString = 0, /// <summary>
/// 调用
/// </summary>
Call = 1, /// <summary>
/// 左相似
/// </summary>
LeftLike = 2, /// <summary>
/// 右相似
/// </summary>
RightLike = 3, /// <summary>
/// 相似
/// </summary>
Like = 4
} /// <summary>
/// 表达式映射
/// </summary>
public static class ExpressionMapper
{
/// <summary>
/// 表达式类型
/// </summary>
public static readonly Dictionary<ExpressionType, string> expressionTypes; /// <summary>
/// 方法调用
/// </summary>
public static readonly Dictionary<string, Action<SqlInfo, MethodCallExpression, Func<Expression, Expression>, Action<ResolveType>>> methodCall; /// <summary>
/// 转换
/// </summary>
public static readonly Action<MethodCallExpression, Func<Expression, Expression>, Action<ResolveType>> convert; /// <summary>
/// 构造方法
/// </summary>
static ExpressionMapper()
{
expressionTypes = new Dictionary<ExpressionType, string>()
{
{ExpressionType.Add,"+" },
{ExpressionType.Subtract,"-" },
{ExpressionType.Multiply,"*" },
{ExpressionType.Divide,"/" },
{ExpressionType.AndAlso,"AND" },
{ExpressionType.OrElse,"OR" },
{ExpressionType.Equal,"=" },
{ExpressionType.NotEqual,"<>" },
{ExpressionType.GreaterThan,">" },
{ExpressionType.LessThan,"<" },
{ExpressionType.GreaterThanOrEqual,">=" },
{ExpressionType.LessThanOrEqual,"<=" }
}; methodCall = new Dictionary<string, Action<SqlInfo, MethodCallExpression, Func<Expression, Expression>, Action<ResolveType>>>()
{
#region 聚合函数
{"Sum", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
visit.Invoke(node.Arguments[0]);
sql.SqlStack.Push("(");
sql.SqlStack.Push("SUM");
} },
{"Max", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
visit.Invoke(node.Arguments[0]);
sql.SqlStack.Push("(");
sql.SqlStack.Push("MAX");
} },
{"Min", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
visit.Invoke(node.Arguments[0]);
sql.SqlStack.Push("(");
sql.SqlStack.Push("MIN");
} },
{"Count", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
visit.Invoke(node.Arguments[0]);
sql.SqlStack.Push("(");
sql.SqlStack.Push("COUNT");
} },
{"Avg", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
visit.Invoke(node.Arguments[0]);
sql.SqlStack.Push("(");
sql.SqlStack.Push("AVG");
} },
#endregion #region 日期函数
{"GetDate", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
sql.SqlStack.Push("(");
sql.SqlStack.Push("GETDATE");
} },
{"Year", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
visit.Invoke(node.Arguments[0]);
sql.SqlStack.Push("(");
sql.SqlStack.Push("YEAR");
} },
{"Month", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
visit.Invoke(node.Arguments[0]);
sql.SqlStack.Push("(");
sql.SqlStack.Push("MONTH");
} },
{"Day", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
visit.Invoke(node.Arguments[0]);
sql.SqlStack.Push("(");
sql.SqlStack.Push("DAY");
} },
{"Current_Timestamp", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
sql.SqlStack.Push("(");
sql.SqlStack.Push("CURRENT_TIMESTAMP");
} },
{"Current_Date", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
sql.SqlStack.Push("(");
sql.SqlStack.Push("CURRENT_DATE");
} },
{"Current_Time", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
sql.SqlStack.Push("(");
sql.SqlStack.Push("CURRENT_TIME");
} },
#endregion #region 数学函数
{"Abs", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
visit.Invoke(node.Arguments[0]);
sql.SqlStack.Push("(");
sql.SqlStack.Push("ABS");
} },
{"Round", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
visit.Invoke(node.Arguments[1]);
sql.SqlStack.Push(",");
visit.Invoke(node.Arguments[0]);
sql.SqlStack.Push("(");
sql.SqlStack.Push("ROUND");
} },
#endregion #region 字符串函数
{"Contains", (sql,node,visit,call)=>
{
call(ResolveType.Like);
visit.Invoke(node.Arguments[0]);
call(ResolveType.SqlString);
sql.SqlStack.Push(" LIKE ");
visit.Invoke(node.Object);
} },
{"StartsWith", (sql,node,visit,call)=>
{
call(ResolveType.LeftLike);
visit.Invoke(node.Arguments[0]);
call(ResolveType.SqlString);
sql.SqlStack.Push(" LIKE ");
visit.Invoke(node.Object);
} },
{"EndsWith", (sql,node,visit,call)=>
{
call(ResolveType.RightLike);
visit.Invoke(node.Arguments[0]);
call(ResolveType.SqlString);
sql.SqlStack.Push(" LIKE ");
visit.Invoke(node.Object);
} },
{"Substring", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
if (node.Arguments.Count > 1)
{
visit.Invoke(node.Arguments[1]);
sql.SqlStack.Push(",");
}
visit.Invoke(node.Arguments[0]);
sql.SqlStack.Push(",");
visit.Invoke(node.Object);
sql.SqlStack.Push("(");
sql.SqlStack.Push("SUBSTRING");
} },
{"Replace", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
visit.Invoke(node.Arguments[1]);
sql.SqlStack.Push(",");
visit.Invoke(node.Arguments[0]);
sql.SqlStack.Push(",");
visit.Invoke(node.Object);
sql.SqlStack.Push("(");
sql.SqlStack.Push("REPLACE");
} },
{"ToUpper", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
visit.Invoke(node.Object);
sql.SqlStack.Push("(");
sql.SqlStack.Push("UPPER");
} },
{"ToLower", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
visit.Invoke(node.Object);
sql.SqlStack.Push("(");
sql.SqlStack.Push("LOWER");
} },
{"Trim", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
visit.Invoke(node.Object);
sql.SqlStack.Push("(");
sql.SqlStack.Push("TRIM");
} },
#endregion #region 其它函数
{"Equals", (sql,node,visit,call)=>
{
visit.Invoke(node.Arguments[0]);
sql.SqlStack.Push(" = ");
visit.Invoke(node.Object);
} },
{"IsNull", (sql,node,visit,call)=>
{
sql.SqlStack.Push(")");
visit.Invoke(node.Arguments[1]);
sql.SqlStack.Push(",");
visit.Invoke(node.Arguments[0]);
sql.SqlStack.Push("(");
sql.SqlStack.Push("ISNULL");
visit.Invoke(node.Object);
} }
#endregion
};
}
} /// <summary>
/// Sql表达式访问
/// </summary>
public class SqlExpressionVisitor : ExpressionVisitor
{ /// <summary>
/// Sql信息
/// </summary>
public readonly SqlInfo sqlInfo; /// <summary>
/// 参数索引
/// </summary>
private readonly Dictionary<string, int> parameterIndex; /// <summary>
/// 成员信息
/// </summary>
private readonly Stack<MemberInfo> memberInfos; /// <summary>
/// 表达式选项
/// </summary>
private readonly SqlExpressionOptions options; /// <summary>
/// 解析类型
/// </summary>
private ResolveType resolveType; /// <summary>
/// 构造方法
/// </summary>
/// <param name="options">表达式选项</param>
public SqlExpressionVisitor(SqlExpressionOptions options, ResolveType resolveType = ResolveType.SqlString)
{
sqlInfo = new SqlInfo();
parameterIndex = new Dictionary<string, int>();
memberInfos = new Stack<MemberInfo>();
this.options = options;
this.resolveType = resolveType;
} /// <summary>
/// 访问
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
[return: NotNullIfNotNull("node")]
public override Expression Visit(Expression node)
{
//Console.WriteLine(node?.NodeType);
return base.Visit(node);
} /// <summary>
/// 访问Lambda
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="node">节点</param>
/// <returns></returns>
protected override Expression VisitLambda<T>(Expression<T> node)
{
if (!options.IgnoreParameterExpression)
{
var index = 0;
foreach (var parameter in node.Parameters)
{
parameterIndex.Add(parameter.Name, index);
index++;
}
}
return Visit(node.Body);
} /// <summary>
/// 访问一元表达式
/// </summary>
/// <param name="node">节点</param>
/// <returns></returns>
protected override Expression VisitUnary(UnaryExpression node)
{
var memberExpression = (node as UnaryExpression).Operand as MemberExpression;
var sqlExpressionVisitor = new SqlExpressionVisitor(options, ResolveType.Call);
var array = (sqlExpressionVisitor.Visit(memberExpression) as ConstantExpression).Value as object[];
return Visit(Expression.Constant(array.Length));
} /// <summary>
/// 访问二元表达式
/// </summary>
/// <param name="node">节点</param>
/// <returns></returns>
protected override Expression VisitBinary(BinaryExpression node)
{
if (node.NodeType == ExpressionType.ArrayIndex)
{
var sqlExpressionVisitor = new SqlExpressionVisitor(options, ResolveType.Call);
var array = (sqlExpressionVisitor.Visit(node.Left) as ConstantExpression).Value as object[];
var value = array[Convert.ToInt32((sqlExpressionVisitor.Visit(node.Right) as ConstantExpression).Value)];
return VisitConstant(Expression.Constant(value));
}
else
{
if (!ExpressionMapper.expressionTypes.ContainsKey(node.NodeType))
{
throw new Exception($"暂不支持{node.NodeType}类型解析");
}
var op = ExpressionMapper.expressionTypes[node.NodeType];
if (node.Right.NodeType == ExpressionType.Constant && ((ConstantExpression)node.Right).Value == null)//判断null值
{
if (op == "=")
{
sqlInfo.SqlStack.Push(" IS NULL");
}
else if (op == "<>")
{
sqlInfo.SqlStack.Push(" IS NOT NULL");
}
}
else
{
if (node.Right is BinaryExpression && node.Right.NodeType == ExpressionType.Equal)
{
sqlInfo.SqlStack.Push(")");
Visit(node.Right);//右边带括号
sqlInfo.SqlStack.Push("(");
}
else
{
Visit(node.Right);//右边
}
sqlInfo.SqlStack.Push($" {op} ");//操作符
}
if (node.Left is BinaryExpression && node.Left.NodeType == ExpressionType.Equal)
{
sqlInfo.SqlStack.Push(")");
Visit(node.Left); //左边带括号
sqlInfo.SqlStack.Push("(");
}
else
{
Visit(node.Left); //左边
}
}
return node;
} /// <summary>
/// 访问索引
/// </summary>
/// <param name="node">节点</param>
/// <returns></returns>
protected override Expression VisitIndex(IndexExpression node)
{
return base.VisitIndex(node);
} /// <summary>
/// 访问参数
/// </summary>
/// <param name="node">节点</param>
/// <returns></returns>
protected override Expression VisitParameter(ParameterExpression node)
{
if (!options.IgnoreParameterExpression)
{
sqlInfo.SqlStack.Push($"p{parameterIndex[node.Name]}.");
}
return node;
} /// <summary>
/// 访问对象
/// </summary>
/// <param name="node">节点</param>
/// <returns></returns>
protected override Expression VisitNew(NewExpression node)
{
if (resolveType == ResolveType.SqlString)
{
for (int i = 0; i < node.Arguments.Count; i++)
{
var name = AddIdentifier(node.Members[i].IsDefined(typeof(ColumnAttribute)) ? node.Members[i].GetCustomAttribute<ColumnAttribute>().Name : node.Members[i].Name);
Visit(node.Arguments[i]);
var value = string.Join("", sqlInfo.SqlStack.ToList());
sqlInfo.NewKeyValues.Add(name, value);
sqlInfo.NewNames.Add(name);
sqlInfo.NewValues.Add(value);
sqlInfo.NewAssignMapper.Add($"{name} = {value}");
sqlInfo.NewAsMapper.Add($"{value} AS {name}");
sqlInfo.SqlStack.Clear();
}
}
else if (resolveType == ResolveType.Call)
{
var sqlExpressionVisitor = new SqlExpressionVisitor(options, ResolveType.Call); var args = new List<object>();
foreach (var item in node.Arguments)
{
args.Add((sqlExpressionVisitor.Visit(item) as ConstantExpression).Value);
} var type = node.Type; object obj = null; if (type.IsGenericTypeDefinition)//泛型类
{
type = type.MakeGenericType(type.GetGenericArguments());
}
if (type.IsDefined(typeof(CompilerGeneratedAttribute)))//匿名对象
{
var argsTypes = args.Select(s => s?.GetType()).ToList().GetTypeDefaultValue();
obj = Activator.CreateInstance(type, argsTypes.ToArray());
for (int i = 0; i < node.Members.Count; i++)
{
var member = node.Members[i];
type.GetField($"<{member.Name}>i__Field", BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance).SetValue(obj, args[i]);
}
}
else
{
obj = Activator.CreateInstance(type, args.ToArray());
}
return VisitConstant(Expression.Constant(obj));
}
return node;
} /// <summary>
/// 访问列表初始化
/// </summary>
/// <param name="node">节点</param>
/// <returns></returns>
protected override Expression VisitListInit(ListInitExpression node)
{
var sqlExpressionVisitor = new SqlExpressionVisitor(options, ResolveType.Call); var args = new List<object>();
args.Add((sqlExpressionVisitor.Visit(node.NewExpression) as ConstantExpression).Value); var type = node.Type;
if (type.IsGenericTypeDefinition)
{
type = type.MakeGenericType(type.GetGenericArguments());
}
var list = Activator.CreateInstance(type, args.ToArray());
foreach (var item in node.Initializers)
{
var args2 = new List<object>();
foreach (var item2 in item.Arguments)
{
args2.Add((sqlExpressionVisitor.Visit(item2) as ConstantExpression).Value);
}
item.AddMethod.Invoke(list, args2.ToArray());
}
if (resolveType == ResolveType.SqlString)
{
return VisitConstant(Expression.Constant(string.Join(",", list)));
} return VisitConstant(Expression.Constant(list));
} /// <summary>
/// 访问对象数组
/// </summary>
/// <param name="node">节点</param>
/// <returns></returns>
protected override Expression VisitNewArray(NewArrayExpression node)
{
var sqlExpressionVisitor = new SqlExpressionVisitor(options, ResolveType.Call); var array = Array.CreateInstance(node.Type.GetElementType(), node.Expressions.Count); for (int i = 0; i < array.Length; i++)
{
array.SetValue((sqlExpressionVisitor.Visit(node.Expressions[i]) as ConstantExpression).Value, i);
} if (resolveType == ResolveType.SqlString)
{
return VisitConstant(Expression.Constant(string.Join(",", array as object[])));
} return VisitConstant(Expression.Constant(array));
} /// <summary>
/// 访问方法
/// </summary>
/// <param name="node">节点</param>
/// <returns></returns>
protected override Expression VisitMethodCall(MethodCallExpression node)
{
if (ExpressionMapper.methodCall.ContainsKey(node.Method.Name) && resolveType == ResolveType.SqlString)
{
ExpressionMapper.methodCall[node.Method.Name].Invoke(sqlInfo, node, e => Visit(e), (type) =>
{
resolveType = type;//回调设置类型
});
}
else
{
var sqlExpressionVisitor = new SqlExpressionVisitor(options, ResolveType.Call);
var args = new List<object>();
foreach (var item in node.Arguments)
{
args.Add((sqlExpressionVisitor.Visit(item) as ConstantExpression).Value);
}
object obj = null;
if (node.Object == null)
{
obj = this;
}
else
{
obj = (sqlExpressionVisitor.Visit(node.Object) as ConstantExpression).Value;
}
var value = node.Method.Invoke(obj, args.ToArray());
resolveType = ResolveType.SqlString;
return Visit(Expression.Constant(value));
}
return node;
} /// <summary>
/// 访问成员初始化
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
protected override Expression VisitMemberInit(MemberInitExpression node)
{
var expressions = (node.Reduce() as BlockExpression).Expressions.Skip(1).SkipLast(1).ToList();//去除不需要的表达式; if (resolveType == ResolveType.SqlString)
{
for (int i = 0; i < expressions.Count; i++)
{
var binaryExpression = (BinaryExpression)expressions[i];
Visit(binaryExpression.Right);
var name = AddIdentifier(node.Bindings[i].Member.IsDefined(typeof(ColumnAttribute)) ? node.Bindings[i].Member.GetCustomAttribute<ColumnAttribute>().Name : node.Bindings[i].Member.Name);
var value = string.Join("", sqlInfo.SqlStack.ToList());
sqlInfo.NewKeyValues.Add(name, value);
sqlInfo.NewNames.Add(name);
sqlInfo.NewValues.Add(value);
sqlInfo.NewAssignMapper.Add($"{name} = {value}");
sqlInfo.NewAsMapper.Add($"{value} AS {name}");
sqlInfo.SqlStack.Clear();
}
}
else if (resolveType == ResolveType.Call)
{
var sqlExpressionVisitor = new SqlExpressionVisitor(options, ResolveType.Call);
var obj = (sqlExpressionVisitor.Visit(node.NewExpression) as ConstantExpression).Value;
for (int i = 0; i < expressions.Count; i++)
{
if (node.Bindings[i].Member.MemberType == MemberTypes.Field)
{
var fields = (FieldInfo)node.Bindings[i].Member;
fields.SetValue(obj, (sqlExpressionVisitor.Visit((expressions[i] as BinaryExpression).Right) as ConstantExpression).Value);
}
if (node.Bindings[i].Member.MemberType == MemberTypes.Property)
{
var propertyInfo = (PropertyInfo)node.Bindings[i].Member;
propertyInfo.SetValue(obj, (sqlExpressionVisitor.Visit((expressions[i] as BinaryExpression).Right) as ConstantExpression).Value);
}
}
return VisitConstant(Expression.Constant(obj));
}
return node;
} /// <summary>
/// 访问成员
/// </summary>
/// <param name="node">节点</param>
/// <returns></returns>
protected override Expression VisitMember(MemberExpression node)
{
memberInfos.Push(node.Member);
if (node.Expression == null && node.NodeType == ExpressionType.MemberAccess)
{
return Visit(Expression.Constant(null));//子表达式为空但有成员处理
}
if (node.Expression.NodeType == ExpressionType.Parameter)
{
if (node.Member.IsDefined(typeof(ColumnAttribute)))
{
sqlInfo.SqlStack.Push(AddIdentifier(node.Member.GetCustomAttribute<ColumnAttribute>().Name));
}
else
{
sqlInfo.SqlStack.Push(AddIdentifier(node.Member.Name));
}
}
return Visit(node.Expression);
} /// <summary>
/// 访问常量
/// </summary>
/// <param name="node">节点</param>
/// <returns></returns>
protected override Expression VisitConstant(ConstantExpression node)
{
var value = node.Value;
if (value != null && value.GetType().FullName.EndsWith("c__DisplayClass0_0"))
{
foreach (var member in memberInfos)
{
if (member.MemberType == MemberTypes.Field)
{
var fieldInfo = (FieldInfo)member;
value = fieldInfo.GetValue(value);
}
else if (member.MemberType == MemberTypes.Property)
{
var propertyInfo = (PropertyInfo)member;
value = propertyInfo.GetValue(value);
}
}
} if (resolveType != ResolveType.Call)
{
if (value != null && value.GetType().Equals(typeof(DateTime)))
{
value = Convert.ToDateTime(value).ToString(options.DateTimeFormat);//格式化日期类型
}
if (memberInfos.Count > 0)
{
var parameterName = Guid.NewGuid().ToString().Replace("-", "");
sqlInfo.SqlStack.Push($"{options.ParameterNotation}{parameterName}");
sqlInfo.SqlParameters.Add(parameterName, AddWildcard(value));
}
else
{
value = AddQuotes(AddWildcard(value));
sqlInfo.SqlStack.Push(Convert.ToString(value));
}
} //最后一个节点初始化
memberInfos.Clear();
return Expression.Constant(value);//返回新的常量表达式
} #region 私有公共方法 /// <summary>
/// 添加引号
/// </summary>
/// <param name="value">值</param>
/// <returns></returns>
private static object AddQuotes(object value)
{
if (value == null)
{
return null;
}
var type = value.GetType();
if (type.Equals(typeof(char)) || type.Equals(typeof(string)) || type.Equals(typeof(DateTime)))
{
return $"'{value}'";
}
return value;
} /// <summary>
/// 添加识别符
/// </summary>
/// <param name="name">名称</param>
/// <returns></returns>
private string AddIdentifier(string name)
{
if (string.IsNullOrWhiteSpace(options.Identifier))
{
return name;
}
return options.Identifier.Insert(1, name);
} /// <summary>
/// 添加通配符
/// </summary>
/// <param name="value">值</param>
/// <returns></returns>
private object AddWildcard(object value)
{
if (resolveType == ResolveType.LeftLike)
{
return $"%{value}";
}
else if (resolveType == ResolveType.RightLike)
{
return $"{value}%";
}
else if (resolveType == ResolveType.Like)
{
return $"%{value}%";
}
return value;
}
#endregion }
}
https://gitee.com/China-Mr-zhong/Fast.Framework 欢迎Star
玩转NET Expression的更多相关文章
- 零元学Expression Blend 4 - Chapter 36 来玩捉迷藏吧!!!看看ScrollBar的Disabled与Hidden之差异
原文:零元学Expression Blend 4 - Chapter 36 来玩捉迷藏吧!!!看看ScrollBar的Disabled与Hidden之差异 本次要针对Disabled以及Hidden作 ...
- [C#] 了解过入口函数 Main() 吗?带你用批处理玩转 Main 函数
了解过入口函数 Main() 吗?带你用批处理玩转 Main 函数 目录 简介 特点 方法的参数 方法的返回值 与批处理交互的一个示例 简介 我们知道,新建一个控制台应用程序的时候,IDE 会同时创建 ...
- 我这么玩Web Api(二):数据验证,全局数据验证与单元测试
目录 一.模型状态 - ModelState 二.数据注解 - Data Annotations 三.自定义数据注解 四.全局数据验证 五.单元测试 一.模型状态 - ModelState 我理解 ...
- [小北De编程手记] : Lesson 05 玩转 xUnit.Net 之 从Assert谈UT框架实践
这一篇,本文会介绍一下基本的断言概念,但重点会放在企业级单元测试的相关功能上面.下面来跟大家分享一下xUnit.Net的断言,主要涉及到以下内容: 关于断言的概念 xUnit.Net常用的断言 关于单 ...
- 玩转spring boot——properties配置
前言 在以往的java开发中,程序员最怕大量的配置,是因为配置一多就不好统一管理,经常出现找不到配置的情况.而项目中,从开发测试环境到生产环境,往往需要切换不同的配置,如测试数据库连接换成生产数据库连 ...
- 转载Entity Framework 4.1 DbContext使用记之三——如何玩转实体的属性值?
Entity Framework 4.1 DbContext使用记之一——如何查找实体? DbSet.Find函数的使用与实现 Entity Framework 4.1 DbContext使用记之二— ...
- 玩转PHP中的正则表达式
玩转PHP中的正则表达式 检验用户输入.解析用户输入和文件内容,以及重新格式化字符串 级别: 中级 正则表达式提供了一种处理文本的强大方法.使用正则表达式,您可以对用户输入进行复杂的检验.解析用户输入 ...
- 工欲善其事,必先利其器 软件工具开发关键词 protractor自动化测试工具 RegexBuddy正则 CodeSmith,LightSwitch:代码生成 CheatEngine:玩游戏修改内存值必备神器 ApkIDE:Android反编译工具 Reflector:反编译dll动态链接库
工欲善其事,必先利其器 本文版权归翟士丹(Stan Zhai)和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利. 原文地址:http ...
- SQL Expression Language Tutorial 学习笔记二
11. Using Textual SQL 直接使用 SQL 如果实在玩不转, 还是可以通过 test() 直接写 SQL. In [51]: s = text( ...: "SELECT ...
随机推荐
- 伪静态 伪装成静态的网址,只是改变URL的表现形式,实际上还是动态页面
路由 Route::get('/list_{id}.html','newsController@listoNewone'); 页面详情 <table class="table" ...
- PHP高并发商城秒杀
1.什么是秒杀 秒杀活动是一些购物平台推出的集中人气的活动,一般商品数量很少,价格很便宜,限定开始购买的时间,会在以秒为单位的时间内被购买一空.比如原价千元甚至万元的商品以一元的价格出售,但数量只有一 ...
- rsyn的使用
以下是rsync的语法: Local: rsync [OPTION...] SRC... [DEST] Access via remote shell: Pull: rsync [OPTION...] ...
- [动态规划] 适合DJ银行的日子
[动态规划] 适合DJ银行的日子 前言:开始的时候用常规模拟做的超时了,然后看官方题解,大致意思就是连续n天单调可以用动态规划的思想 你和一群强盗准备打劫银行.给你一个下标从 0 开始的整数数组 se ...
- 移动端ios网页版收起键盘导致页面空白解决办法
失焦的时候把窗口滚动位置设置到(0,0)就行了 <input type="text" onblur="window.scrollTo(0, 0);"> ...
- docker容器登录,退出等操作命令
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口 ...
- Spring Boot 的配置文件有哪几种格式?它们有什么区别?
.properties 和 .yml,它们的区别主要是书写格式不同. 1).properties app.user.name = javastack 2).yml app: ...
- phpstorm chrome 添加xdebug扩展
转:https://blog.csdn.net/ltcm_sakura/article/details/102967859 一.Xdebug helper:php调试插件 http://chromec ...
- Error 和 Exception 有什么区别?
Error 表示系统级的错误和程序不必处理的异常,是恢复不是不可能但很困难的情 况下的一种严重问题:比如内存溢出,不可能指望程序能处理这样的情况: Exception 表示需要捕捉或者需要程序进行处理 ...
- 为什么 wait()方法和 notify()/notifyAll()方法要在同步块 中被调用 ?
这是 JDK 强制的,wait()方法和 notify()/notifyAll()方法在调用前都必须先获得对 象的锁