你的位置:首页 > ASP.net教程

[ASP.net教程]EF的缓存设计


对于EF对数据库的缓存,EF本身也有,但是不能灵活的控制,而且实体对象释放了缓存就没有了,总不能使用同一个实体对象(实体对象不支持多线程),基本上就是用完就释放,而EF的一个扩展框架也提供了缓存操作(源码:https://github.com/loresoft/EntityFramework.Extended),大体的操作:

//默认配置的缓存var tasks = db.Tasks.Where(t => t.CompleteDate == null).FromCache(); //设置缓存时间300svar 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;    }   }