CRL4.5版本已经稳定使用于目前的几个中型项目中,在实际使用中,也发现了不少问题,这些问题都在4.52中提交

CRL具体功能和使用请浏览 CRL快速开发框架系列教程

由于现在项目是一套业务系统,查询需求比较多,CRL带的语法解析都能满足,特殊的可手写SQL,在针对查询的优化,以下几点

对查询调用的监视

由于业务封装写得非常复杂,方法嵌套很严重,无法检查一个方法内有多少查询,需不需要优化,因此使用CallContext进行了监视,并生成报表

        public ActionResult RunTime()
        {
            var str = CRL.Runtime.RunTimeService.Display();
            return Content(str);
        }

最终如下图:

路径:表示调用方法的路径

DBCall:表示实例化的数据管理类

ALLCall:表示所有数据访问调用

表达式解析内存占用

在一次更新中,为了使解析速度更快,将表达式进行了缓存,只有参数进行了重解析,看上去是省了不少,如下所示

 CRLExpression.CRLExpression BinaryExpressionHandler(Expression left, Expression right, ExpressionType expType)
var key = string.Format("{0}{1}{2}{3}", __PrefixsAllKey, left, expType, right);
var a = BinaryExpressionCache.TryGetValue(key, out cacheItem);
if (a)
  {
返回缓存
}

但是Expression left.ToString()效率并不高,并且占内存,所以这个并没有什么卵用

字符串变量内存占用

因为CRL查询所有参数都需要进行参数化,因此需要对应的参数名,如以下表达式:b=>b.Id==1

参数名为:@p1,若再有参数,依次类推,然而@p1由 string.Format("{0}p{1}","@",1)生成,在对性能测试时发现,这个Format占用了很多内存

于是解决办法,还是缓存参数名,提前生成,重复使用

if (parameDic == null)
            {
                parameDic = new Dictionary<int, string>();
                for (int i = 0; i <= 5000; i++)
                {
                    parameDic.Add(i, __DBAdapter.GetParamName("p", i));
                }
            }
var _par = parameDic[parIndex];
AddParame(_par, par);

字段格式化内存占用

CRL查询默认是查询所有字段,所以查询为 select t1.Id,t1.Name,t1.Code.....,在没有手动选择查询字段时,这些select其实一直是一样的,通过性能监视发现,好多内存被这重复解析占用了

优化后,当是查询所有字段,从缓存里生成

if (GetPrefix(__MainType) == "t1.")
            {
                key = __MainType.ToString();
                SelectFieldInfo value;
                var a = queryFieldCache.TryGetValue(key, out value);
                if (a)
                {
                    if (!cacheAllFieldString)
                    {
                        var item = value.Clone();
                        item.CleanQueryFieldString();
                        _CurrentSelectFieldCache = item;
                    }
                    else
                    {
                        _CurrentSelectFieldCache = value;
                    }
                    return;
                }
                cache = true;
            }

因为CRL对查询作了关键字处理,包括表名,字段名,所以最终的语句为

以MSSQL为例:select t1.[Name] from [table1] t1

方法为

        public override string KeyWordFormat(string value)
        {
            return string.Format("[{0}]", value);
        }

实际上,每个字段只用生成一次就行了,再次使用时从缓存中取,节省了不少内占用

        public string FieldNameFormat(Attribute.FieldAttribute field)
        {
            if (string.IsNullOrEmpty(field.MapingNameFormat))
            {
                field.MapingNameFormat = KeyWordFormat(field.MapingName);
            }
            return field.MapingNameFormat;
        }

手写语句提取参数

直接将参数拼在SQL里好像不怎么雅观,并且,容易造成语法错误和注入漏洞,如下:

string sql = "select top 10 Id,ProductId,ProductName1 from ProductData a where a.addtime>='2017-09-01' and a.id=234";
            var helper = DBExtend;
            var list = helper.ExecDynamicList(sql);

CRL新增了方法,能重新处理手写的SQL为参数化

int parIndex = 1;
        /// <summary>
        /// 提取SQL参数
        /// </summary>
        /// <param name="db"></param>
        /// <param name="sql"></param>
        /// <param name="manual"></param>
        /// <returns></returns>
        public virtual string ReplaceParameter(CoreHelper.DBHelper db,string sql,bool manual = false)
        {
            if (!SettingConfig.ReplaceSqlParameter && !manual)
            {
                return sql;
            }
            //return sql;
            var re = @"((\s|,)*)(\w+)\s*(>|<|=|!=|>=|<=)\s*('(.*?)'|([1-9]\d*.\d*|0.\d*[1-9]\d*))(\s|,|\))";
            sql = sql + " ";
            if (!Regex.IsMatch(sql, re, RegexOptions.IgnoreCase))
            {
                return sql;
            }
            Regex r = new Regex(re, RegexOptions.IgnoreCase);
            List<string> pars = new List<string>();
            //int index = 1;
            for (var m = r.Match(sql); m.Success; m = m.NextMatch())
            {
                var name = m.Groups[3];
                var op = m.Groups[4];
                var value1 = m.Groups[6];
                var value2 = m.Groups[7];
                var value = string.IsNullOrEmpty(value2.Value) ? value1 : value2;
                var p = m.Groups[1];
                var p2 = m.Groups[8];
                var pName = GetParamName("_p", parIndex);
                db.AddParam(pName, value.ToString());
                sql = sql.Replace(m.ToString(), string.Format("{0}{1}{4}{2}{3} ", p, name, pName, p2, op));
                parIndex += 1;
            }
            return sql;
        }

在配置为自动替换SQL拼接参数(CRL.SettingConfig.ReplaceSqlParameter=true),实际输出将为:

select top 10 Id,ProductId,ProductName1 from ProductData a where a.addtime>=@p1 and a.id=@p2

异步插入MSMQ的实现

在某个业务中,一张表很频繁的单个插入,占用大量资源,专门为这写个消息队列好像不怎么高明,下次又有这样的情况怎么办

于是有就了,为每个对象定义自已的消息队列和处理,用第三方的不太好集成,就是微软自家的吧

        /// <summary>
        /// 添加一条记录[基本方法]
        /// 异步时,会定时执行批量插入,依赖MSMQ服务
        /// </summary>
        /// <param name="p"></param>
        /// <param name="asyn">异步插入</param>
        public virtual void Add(TModel p, bool asyn = false)
        

调用参数为true时,则为TModel类型创建消息队列,并异步分批次插入到数据库中,比如在10秒内连续调用了100次此方法

只是将数据存入了消息队列,在队列下个处理周期,将这100条批量插入到数据库,效率倍增

DbSet方式的实现

在Entity Framework里,有DbSet的概念,配置好数据关系后,关联对象直接就能取到了

在CRL里,简单实现一下

public class Order : CRL.IModelBase
{

    public CRL.Set.DbSet<ProductData> Products//返回关联的Product
        {
            get
            {
                return GetDbSet<ProductData>(b => b.Id, ProductId);
            }
        }
        public CRL.Set.EntityRelation<Member> Member//返回关联的Member
        {
            get
            {
                return GetEntityRelation<Member>(b => b.Id, UserId);
            }
        }
}

调用如下:

var order = new Code.Order();
            //所有
            var product = order.Products.ToList();

            //返回关联过的查询,使用完整查询满足更多需求
            var product2 = order.Products.GetQuery();

            var p = new Code.ProductData() { BarCode = "33333" };
            //添加一项
            order.Products.Add(p);

            order.Products.Delete(p);//删除一项

            //返回完整的BaseProvider
            var provider = order.Products.GetProvider();

            //返回关联的member,在调用时返回,在循环内调用会多次调用数据库
            var member = order.Member.Value;

十年磨一剑,在代码写得越来越深入,再回头看自已的代码,残破不堪.

欢迎下载源码交流讨论

获取CRL最新源码见文章底部下载

CRL快速开发框架升级到4.52,谈谈开发过程中的优化的更多相关文章

  1. 非关系型数据库来了,CRL快速开发框架升级到版本4

    轮子?,我很任性,我要造不一样的轮子,同时支持关系型和非关系型的框架有没有 新版数据查询作了些调整,抽象了LabmdaQueryy和DBExtend,升级到版本4,非关系数据库MongoDB被支持了! ...

  2. CRL快速开发框架升级到3.1

    CRL是一款面向对象的轻量级ORM框架,本着快速开发,使用简便的原则,设计为 无需关心数据库结构,CRL自动维护创建,即写即用(CRL内部有表结构检查机制,保证表结构一致性) 无需第三方工具生成代理类 ...

  3. CRL快速开发框架开源完全转到Github

    CRL简介 CRL是一款面向对象的轻量级ORM框架,本着快速开发,使用简便的原则,设计为 无需关心数据库结构,CRL自动维护创建,即写即用(CRL内部有表结构检查机制,保证表结构一致性) 无需第三方工 ...

  4. CRL快速开发框架系列教程十三(嵌套查询)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  5. CRL快速开发框架系列教程十二(MongoDB支持)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  6. CRL快速开发框架系列教程十一(大数据分库分表解决方案)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  7. CRL快速开发框架系列教程十(导出对象结构)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  8. CRL快速开发框架系列教程九(导入/导出数据)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  9. CRL快速开发框架系列教程七(使用事务)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

随机推荐

  1. [转载] Linux curl命令详解

    转载自http://www.linuxdiyf.com/linux/2800.html 命令:curl在Linux中curl是一个利用URL规则在命令行下工作的文件传输工具,可以说是一款很强大的htt ...

  2. [转载] 网络IO模型

    转载自http://blog.csdn.net/zhoudaxia/article/details/8974779 同步(synchronous) IO和异步(asynchronous) IO,阻塞( ...

  3. [转载] Dubbo架构设计详解

    转载自http://shiyanjun.cn/archives/325.html Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合 ...

  4. Python的路径引用

    1.以HOME目录为准,进行跳转 sys.path.append(os.path.dirname(__file__) + os.sep + '../') from config import swor ...

  5. 使用JavaScript生成二维码教程-附qrcodejs中文文档

    使用javascript生成二维码 依赖jquery 需要使用到的库 https://github.com/davidshimjs/qrcodejs DIV <div id="qrco ...

  6. 【Java框架型项目从入门到装逼】第三节 - 如何用Tomcat发布web项目?

    啥叫Tomcat?有道词典是这么说的. 这个我们姑且不管,实际上呢,Tomcat是一种Web服务器,我们自己做好了一个Web项目,就可以通过Tomcat来发布.服务器呢,又分为硬件服务器和软件服务器. ...

  7. HTML5将给企业带来什么?

    HTML5是近几年来互联网行业的热门词汇,火热的厉害,未来的网络属于HTML5. 乔布斯生前也在公开信<Flash之我见>中预言:像HTML5这样在移动时代中创立的新标准,将会在移动设备上 ...

  8. hive中一些常用的sql语句

    1.建表 CREATE TABLE IF NOT EXISTS student( time varchar(64) , num int , age int )PARTITIONED BY ( scor ...

  9. asp.net core 实现一个简单的仓储

    一直有自己写个框架的想法,但是一直没有行动起来,最近比较闲,正好可以开工了. 现在已经完成了两部分.1.一个简单仓储,实现使用的是ef 2.IOC部分,这里是把内置的ioc替换成了aotofac,这部 ...

  10. Linux系统安装-MacBook网卡驱动问题解决

    先附上MacBook的linux安装教程 需要注意的是第7步中可能无法识别出OS X的系统,也没关系,只要格式化磁盘的时候注意选择对应磁盘即可,格式化成EXT4分区. 安装好后发现无法连接无线网络,应 ...