EF的缓存设计

对于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;

        }

    }
时间: 2024-08-18 18:22:39

EF的缓存设计的相关文章

分布式系统缓存设计浅析

1. 分布式缓存面临比较大的三个问题: (1) 数据一致性. 在分布式系统这点显得尤为重要,主要原因有三点: 缓存系统与底层数据的一致性.这点在底层系统是“可读可写”时,写得尤为重要 有继承关系的缓存之间的一致性.为了尽量提高缓存命中率,缓存也是分层:全局缓存,二级缓存.他们是存在继承关系的.全局缓存可以有二级缓存来组成. 多个缓存副本之间的一致性.为了保证系统的高可用性,缓存系统背后往往会接两套存储系统(如memcache,redis等),以上的ppt也主要是讲这方面的内容. (2)缓存雪崩

【转】缓存设计的一些思考

***{转自:缓存设计的一些思考}*** 互联网架构中缓存无处不在,某厂牛人曾经说过:”缓存就像清凉油,哪里不舒服,抹一下就好了”.高品质的存储容量小,价格高:低品质存储容量大,价格低,缓存的目的就在于”扩充”高品质存储的容量.本文探讨缓存相关的一些问题. LRU替换算法 缓存的技术点包括内存管理和替换算法.LRU是使用最多的替换算法,每次淘汰最久没有使用的元素.LRU缓存实现分为两个部分:Hash表和LRU链表,Hash表用于查找缓存中的元素,LRU链表用于淘汰.内存常以Slab的方式管理.

21、缓存设计

? 什么是缓存 缓存一般是磁盘或内存中的存储区域,用于存储从网络或其他数据源 获取的文件.通常这些数据源的访问速度远低于缓存的访问速度.使用 缓存可以大大提高程序的运行效率,但数据不会实时更新. ? 缓存设计原理  这里以ListView为例.在ListView上显示多个从网络上下载的图片. 如果是第一次运行程序,需要实时从网络上下载这些图片文件.但由于 网络速度的原因,如果一边下载.一边显示,ListView就会有些卡.所以 我们采用了缓存技术,也就是说,当ListView显示网络上某个图片时

由Android缓存设计想到的

由Android缓存设计想到的 前言 Android这种对内存比较敏感的系统,在处理大量图片的时候不可避免要用到缓存,那么到底是应该使用虚拟机底层通过GC回收保障的SoftReference,还是使用一个带LRU算法的队列,哪个更适合Android系统下的应用? 基本概念 缓存,顾名思义把已经读取到的数据存下来,供再次读取,合理的使用缓存可以减少一些昂贵代价的动作(数据库操作,文件读写,网络传输,等),缓解系统压力,提高程序响应速度. 设计缓存需要注意的几个方面:缓存的容量,如何使缓存维持在一个

百万级运维经验五:网站缓存设计

大访问量的网站少不了缓存,那如何设计网站的缓存呢? 网站缓存可以有很多种: 1.根据数据表和主键缓存单条数据,如每个用户,每篇文章等等. 2.缓存数据列表,通常用于显示多条数据的地方.如缓存前200篇文章,因为一般前200条数据的查询次数是最多的. 3.缓存模板块,比如某个页面,其中一部分的内容是很少变动的,可以把这部分内容缓存起来. 4.缓存整个页面,比如首页,当程序生成整个页面的内容时,把内容缓存起来,下次访问时直接从缓存里取. 5.数据统计缓存,如评论数.收藏数等. 目前我所了解的是这4钟

CYQ.Data V5 分布式自动化缓存设计介绍(二)

前言: 最近一段时间,开始了<IT连>创业,所以精力和写的文章多数是在分享创业的过程. 而关于本人三大框架CYQ.Data.Aries.Taurus.MVC的相关文章,基本都很少写了. 但框架的维护升级,还是时不时的在进行中的,这点从开源的Github上的代码提交时间上就可以看出来了. 毕竟<IT连>的后台WebAPI,用的是Taurus.MVC,后台系统管理用的是Aries. 不过今天,就不写创业相关的文章了,先分享篇技术类的文章. CYQ.Data 分布式自动缓存 之前写过一篇

nginx+Memcached 缓存设计

单页面缓存方案 单静态页缓存 解决问题场景 常见的缓存设计利用System.Web.Cache 保存在内存内,效率高,可以减轻数据库访问的压力.但是Web除了获取数据之外,还有呈现页面渲染,生成HTML很多功能都是消耗性能.在Web层也需要一个缓存,同时柔性设计,应用代码不需要大变动. 架构 客户端 访问 /Report Nginx 接收请求,判断Memcached是否存在以该网址的Key,存在直接返回不经过IIS,不存在 ,透传到IIS,并在Memacched中保存 优势:memcached性

本地缓存设计

被问到本地缓存设计,有点蒙,事后反应过来,何必一个Map呢,两个就可以解决了.真是当时脑子短路了. package cache; import java.util.Map;import java.util.concurrent.ConcurrentHashMap; public class MyCache<K, V> { private static class ValueObject<T> { private T value; private long timeout; priv

MyBatis缓存设计

和大多数ORM框架一样,为了尽可能减少数据库的访问,MyBatis设计支持缓存功能.设计上通过Cache接口提供SPI(服务提供接口),可以让第三方缓存提供具体的缓存实现,比如使用ehcache.Redis等,通过这些常用环境提供的实现类,即可将其配置成MyBatis中使用的缓存. 除了给第三方缓存提供SPI接口外,MyBatis自身也通过HashMap做了简单的缓存实现.总体上MyBatis缓存设计分为一级缓存和二级缓存. MyBatis一级缓存是SqlSession级别的本地缓存,默认开启不