對於EF對資料庫的緩存,EF本身也有,但是不能靈活的控制,而且實體對象釋放了緩存就沒有了,總不能使用同一個實體對象(實體對象不支持多線程),基本上就是用完就釋放,而EF的一個擴展框架也提供了緩存操作(源碼:https://github.com/loresoft/EntityFramework.Ext ...
對於EF對資料庫的緩存,EF本身也有,但是不能靈活的控制,而且實體對象釋放了緩存就沒有了,總不能使用同一個實體對象(實體對象不支持多線程),基本上就是用完就釋放,而EF的一個擴展框架也提供了緩存操作(源碼:https://github.com/loresoft/EntityFramework.Extended),大體的操作:
//預設配置的緩存 var tasks = db.Tasks .Where(t => t.CompleteDate == null) .FromCache(); //設置緩存時間300s var tasks = db.Tasks .Where(t => t.AssignedId == myUserId && t.CompleteDate == null) .FromCache(CachePolicy.WithDurationExpiration(TimeSpan.FromSeconds(300)));
看了下這個擴展框架源碼是如何對linq表達式進行解析的,主要是繼承ExpressionVisitor(採用訪問者模式)進行解析,其中有段代碼是最重要的了:
private Expression Evaluate(Expression e) { if (e.NodeType == ExpressionType.Constant) { return e; } LambdaExpression lambda = Expression.Lambda(e); Delegate fn = lambda.Compile(); return Expression.Constant(fn.DynamicInvoke(null), e.Type); }
上面代碼中調用DynamicInvoke會對Where中的變數進行解析為實際值,例如上面的Where中的t.AssignedId會解析為實際的值;用著還是挺好的,但是做了次性能分析,發現DynamicInvoke的調用非常費性能(看到了dynamic字頭的也知道會費性能的了),那麼要麼硬著頭皮去用,要麼就重新對Expression進行解析了,下麵是對上面代碼改進:
private Expression Evaluate(Expression e) { if (e.NodeType == ExpressionType.Constant) { return e; } if (e is MemberExpression) { var expmember = ExpressionVisitorHelper.GetMemberExpression(e); if (expmember != null) { return expmember; } } return ExpressionVisitorHelper.GetMethodCallExpression(e); } //ExpressionVisitorHelper類: internal static class ExpressionVisitorHelper { public static Expression GetMethodCallExpression(Expression e) { object val = null; if (e is MethodCallExpression) { val = DoToGetMethodCallVal(e as MethodCallExpression); } else if (e is UnaryExpression) { val = GetUnaryExpressionVal(e as UnaryExpression); } if (val == null || val.GetType() != e.Type) { LambdaExpression lambda = Expression.Lambda(e); return Expression.Constant(lambda.Compile().DynamicInvoke(null), e.Type); } else { return Expression.Constant(val, e.Type); } } public static Expression GetMemberExpression(Expression exp) { var val = GetMemberExpVal(exp); if (val != null) { return Expression.Constant(val, exp.Type); } return null; } static object GetUnaryExpressionVal(UnaryExpression exp) { var val = GetMemberExpVal(exp.Operand); if (val == null) { val = GetConstantExpVal(exp.Operand, null); } return val; } static object DoToGetMethodCallVal(MethodCallExpression expMethod) { //可能出現的問題expMethod.Object又是一個MethodCallExpression,例如:l.Serverid.StartsWith(model.Name.TrimEnd().TrimStart().ToLower()) object val = null; if (expMethod.Object is MethodCallExpression) { Expression tempExp = expMethod.Object; MethodCallExpression tempExpMethod; var listMemberExp = new List<MethodCallExpression>(); while (tempExp is MethodCallExpression) { tempExpMethod = tempExp as MethodCallExpression; listMemberExp.Add(tempExpMethod); tempExp = tempExpMethod.Object; } //進行第一個Method的調用(TrimEnd): tempExpMethod = listMemberExp[listMemberExp.Count - 1]; val = GetMemberExpVal(tempExpMethod.Object); val = GetMethodCallVal(tempExpMethod, val); //迴圈調用其餘的Method(TrimStart) for (int i = listMemberExp.Count - 2; i >= 0; i--) { val = GetMethodCallVal(listMemberExp[i], val); } //進行最後一個Method的調用(ToLower) val = GetMethodCallVal(expMethod, val); } else { val = GetMemberExpVal(expMethod.Object); val = GetMethodCallVal(expMethod, val); } return val; } static object GetMethodCallVal(MethodCallExpression expMethod, object val) { if (val != null) { switch (expMethod.Method.Name) { case "ToString": case "ToLower": case "ToUpper": { val = expMethod.Method.Invoke(val, null); } break; case "Trim": case "TrimStart": case "TrimEnd": { object[] objArray = null; if (expMethod.Arguments != null && expMethod.Arguments.Count > 0) { NewArrayExpression arg = null; ConstantExpression expConst = null; objArray = new object[expMethod.Arguments.Count]; char[] valArray = null; for (int i = 0, j = 0; i < expMethod.Arguments.Count; i++) { arg = expMethod.Arguments[i] as NewArrayExpression; if (arg != null && arg.Expressions != null && arg.Expressions.Count > 0) { valArray = new char[arg.Expressions.Count]; for (j = 0; j < arg.Expressions.Count; j++) { expConst = arg.Expressions[j] as ConstantExpression; if (expConst != null) { valArray[j] = (char)expConst.Value; } } } objArray[i] = valArray; } } val = expMethod.Method.Invoke(val, objArray); } break; default: break; } } return val; } static object GetMemberExpVal(Expression exp) { if (exp is MemberExpression) { var node = exp as MemberExpression; if (node.Expression is MemberExpression) { MemberExpression lastMemberExp; List<MemberExpression> listMemberExp; var constExp = MemberExpToConstantExp(node.Expression, out lastMemberExp, out listMemberExp); var constVal = GetConstantExpVal(constExp, lastMemberExp.Member); if (constVal != null) { if (listMemberExp != null && listMemberExp.Count > 0) { for (int i = listMemberExp.Count - 1; i >= 0; i--) { constVal = GetMemberVal(listMemberExp[i].Member, constVal); } return GetMemberVal(node.Member, constVal); } else { return GetMemberVal(node.Member, constVal); } } } else if (node.Expression is ConstantExpression) { return GetConstantExpVal(node.Expression, node.Member); } else if (node.Expression == null) { //獲取靜態的成員數據 return GetConstantExpVal(node.Expression, node.Member); } } return null; } static object GetConstantExpVal(Expression exp, MemberInfo member) { object val = null; if (exp is ConstantExpression) { val = (exp as ConstantExpression).Value; if (member != null) { val = GetMemberVal(member, val); } } else if (exp == null) { //獲取靜態的成員數據 val = GetMemberVal(member, member.Name); } return val; } static object GetMemberVal(MemberInfo member, object obj) { object val = null; if (member is PropertyInfo) { val = (member as PropertyInfo).GetValue(obj); } else if (member is FieldInfo) { val = (member as FieldInfo).GetValue(obj); } return val; } // 獲取最後的MemberExpression和ConstantExpression static Expression MemberExpToConstantExp(Expression exp, out MemberExpression lastMemberExp, out List<MemberExpression> listMemberExp) { lastMemberExp = null; listMemberExp = new List<MemberExpression>(); while (exp is MemberExpression) { if (lastMemberExp != null) { listMemberExp.Add(lastMemberExp); } lastMemberExp = exp as MemberExpression; exp = lastMemberExp.Expression; } return exp; } }