首页 技术 正文
技术 2022年11月15日
0 收藏 307 点赞 2,739 浏览 12594 个字

.Net Core ORM选择之路,哪个才适合你

 

因为老板的一句话公司项目需要迁移到.Net Core ,但是以前同事用的ORM不支持.Net Core 开发过程也遇到了各种坑,插入条数多了也特别的慢,导致系统体验比较差好多都改写Sql实现。

所以我打算找一款

性能比较好

功能比较完善

方便以后可以切换数据库(经过我对老板的了解这个功能非常重要)

并且要有一定用户基础的ORM

参赛ORM

能够参赛的ORM必须要有以下个条件

第一、功能方面要比较完善

第二、Github需要有一定人气并且最近有更新

第三、支持多种数据库少写Sql,方便以后

筛选结果:

1、EF Core

2、Dapper+扩展

3、SqlSugar Core

4、Nhibernate Core

5、PetaPoco

第一轮淘汰赛  我们比 人气&功能

经过对这几个ORM的初步了解,对功能方面和人气方面进行了初步评分

1、EF Core     人气10,功能10

2、Dapper+扩展  人气10,功能9

3、SqlSugar Core  人气7,功能10

4、Nhibernate Core 人气7,功能10

5、PetaPoco 人气6,功能6

经过第一轮帅选,我淘淘汰了PetaPoco ORM

最重要的是这个ORM定位比较尴尬 ,功能一般并且扩展插件也比较稀少。现有功能以拼Sql为主满足不了我以后切换数据库的需求,第一轮淘态。

第一轮得分排名

1、EF Core 胜出

2、Dapper+扩展   胜出

3、SqlSugar Core  ,Nhibernate Core 胜出

4、PetaPoco 淘汰

第二轮淘汰赛 我们比易用性

写太牛逼的功能并不是我们所考虑的,需要上手快好用,于是我针对项目中几个需求点进行了上手测试,并给出了评分

1、EF Core  10   轻松满足

2、Dapper+扩展   8  需要找插件比较费时间

3、SqlSugar Core 10   轻松满足

4、Nhibernate Core  1 完全不会用

第二轮得分排名

1、EF Core,SqlSugar Core   胜出

2、Dapper+扩展   胜出

3、Nhibernate Core  淘汰

能够通过精心挑选并且进入前3名,相信这3个ORM都有他们独自的魅力

第三轮淘汰赛 我们比性能

经过对 批量插入、单条插入、批量更新、单条更新、条件查询、多选删除等几种常用场景的并发测试

我意外的发现SqlSugar性能比Dapper更加的优秀,EF Core垫底

第三轮得分排名

1、SqlSugar Core   胜出

2、Dapper+扩展   胜出

3、EF Core  淘汰

通过上面各种环节我们可以发现,我都会淘汰每场比赛表现最差者,因为我想找一个比较平衡的ORM用于项目,不想有短腿。

决赛 我们比大家的建议

目前Dapper+扩展和SqlSugar Core  这2个ORM是最适合我们的团队的,同事之间也各有说词,暂且平手吧。明天我们公司会在进行讨论。写个博文让大家给给建议,进行最终定夺。

下面是这2款ORM地址:

Dapper

https://github.com/StackExchange/Dapper

https://github.com/tmsmith/Dapper-Extensions

SqlSugar

https://github.com/sunkaixuan/SqlSugar

通用查询类封装之Mongodb篇

 

  查询在应用程序中很重要,花样也特别多,不同得业务需求需要不同的查询条件,还要支持and、or ……事实上也确实如此,程序中有N多个查询类,并且很可能其中有多个类查询同一张表,所以特别想弄一个通用的查询类。

  前几天也是因为讨论有关查询的问题,想到了一个点子觉得可行,最近就抓紧实现了一下来验证想法的可行性……

  思路:其实查询类很简单,无非就是你要查询哪个字段—字段名称(Key)、你想搜索的值—字段值(Value)、以及如何进行比较—查询类型(QueryType),这是单个查询条件(之后都叫做查询因子,不知道合适不合适,也是突然间想起来的),如果是多个条件,弄了一个集合就是好了,问题就在于这些查询因子之间的关系(and、or)……既然叫做查询因子,这个集合我们不管他们之间的关系,只是简单的查询因子的集合,我们在弄一个字段来存储他们之间的关系,这里暂时叫做逻辑表达式,例如:((a|b)&c)|((a&b&d)|e),最后我就解析这个表达式就可以了,a、b、c、d、e只要在集合中找到具体的哪个查询因子就可以了,就是这样了。说通用查询类有点惭愧,目前只是在Mongodb下弄了一个简单的实现(重点是思路了,嘿嘿),因为项目上用的是Mongodb所以先实现的肯定是他了,其他的数据库同理……

.Net Core ORM选择之路,哪个才适合你  通用查询类封装之Mongodb篇  Snowflake(雪花算法)的JavaScript实现  【开发记录】如何在B/S项目中使用中国天气的实时天气功能   【开发记录】微信小游戏开发入门——俄罗斯方块

/// <summary>/// 通用查询类/// </summary>public class QueryModel{    /// <summary>    /// 逻辑表达式    /// </summary>    public string FilterStr { get; set; }    /// <summary>    /// 查询因子字典集合    /// </summary>    public Dictionary<string, QueryFactor> DCQueryFactor { get; set; }}/// <summary>/// 查询因子类/// </summary>public class QueryFactor{    /// <summary>    /// 查询字段的名称    /// </summary>    public string Key { get; set; }    /// <summary>    /// 查询字段的值    /// </summary>    public object Value { get; set; }    /// <summary>    /// 比较类型,支持的类型有:    /// eq:等于,    /// ne:不等于    /// gt:大于    /// lt:小于    /// gte:大于等于    /// lte:小于等于    /// in:范围查询    /// like:模糊查询    /// </summary>    public string QueryType { get; set; } = "eq";}

.Net Core ORM选择之路,哪个才适合你  通用查询类封装之Mongodb篇  Snowflake(雪花算法)的JavaScript实现  【开发记录】如何在B/S项目中使用中国天气的实时天气功能   【开发记录】微信小游戏开发入门——俄罗斯方块

  这个倒是没有什么,关键是这个所谓的逻辑表达式不知道如何解析,真是废了半天劲儿……什么类似的堆栈实现计算器、逆波兰式等弄了一大堆,感觉都没有用上,最后对一个例子做了一些改进,才完成的……

.Net Core ORM选择之路,哪个才适合你  通用查询类封装之Mongodb篇  Snowflake(雪花算法)的JavaScript实现  【开发记录】如何在B/S项目中使用中国天气的实时天气功能   【开发记录】微信小游戏开发入门——俄罗斯方块

public class QueryModelForMongodb{    private Dictionary<string, FilterDefinition<BsonDocument>> ParenthesesExpressionDic = new Dictionary<string, FilterDefinition<BsonDocument>>();    /// <summary>    /// 入口方法    /// </summary>    /// <param name="logicalExpression">逻辑表达式</param>    /// <param name="queryModel">查询类</param>    /// <returns></returns>    public FilterDefinition<BsonDocument> ToMongodbFilter(string logicalExpression, QueryModel queryModel)    {        int startIndex = logicalExpression.LastIndexOf("(");        if (startIndex != -1)        {            //  截取括号中的表达式            int endIndex = logicalExpression.IndexOf(")", startIndex);            int len = endIndex - startIndex - 1;            string simpleExpress = logicalExpression.Substring(startIndex + 1, len);            //  处理简单的表达式并结果保存到字典中            string tempGuid = Guid.NewGuid().ToString();            FilterDefinition<BsonDocument> fd1 = ToMongodbFilterSimpleLogicalExpression(simpleExpress, queryModel);            ParenthesesExpressionDic.Add(tempGuid, fd1);            //  继续处理剩余表达式            string leftStr = logicalExpression.Substring(0, startIndex);            string rightStr = logicalExpression.Substring(endIndex + 1);            return ToMongodbFilter($"{leftStr}{tempGuid}{rightStr}", queryModel);        }        return ToMongodbFilterSimpleLogicalExpression(logicalExpression, queryModel);    }    /// <summary>    /// 处理简单的逻辑表达式(不包含圆括号)    /// </summary>    /// <param name="logicalExpression"></param>    /// <param name="queryModel"></param>    /// <returns></returns>    private FilterDefinition<BsonDocument> ToMongodbFilterSimpleLogicalExpression(string logicalExpression, QueryModel queryModel)    {        //  1、筛选出操作符:&、|        Queue<char> qOperator = new Queue<char>();        //Regex regexOperator = new Regex("[&|]");        //foreach (Match item in regexOperator.Matches(logicalExpression))        //{        //    qOperator.Enqueue(item.Value);        //}        foreach (char c in logicalExpression)        {            if (c == '&' || c == '|')            {                qOperator.Enqueue(c);            }        }        //  2、筛选出所有的变量        Queue<string> qVariable = new Queue<string>();        string[] tempVariables = logicalExpression.Replace("&", ",").Replace("|", ",").Split(",");        foreach (string v in tempVariables)        {            qVariable.Enqueue(v);        }        //  3、返回结果组装        FilterDefinition<BsonDocument> filter = null;        if (qVariable.Count >= 1)        {            string tempV = qVariable.Dequeue();            filter = ParenthesesExpressionDic.ContainsKey(tempV) ? ParenthesesExpressionDic[tempV] : QueryFactorToMogodbFilter(queryModel.DCQueryFactor[tempV]);            while (qVariable.Count > 0)            {                string rightV = qVariable.Dequeue();                var tempFilter = ParenthesesExpressionDic.ContainsKey(rightV) ? ParenthesesExpressionDic[rightV] : QueryFactorToMogodbFilter(queryModel.DCQueryFactor[rightV]);                char tempOperator = qOperator.Dequeue();                switch (tempOperator)                {                    case '&':                        {                            filter = filter & tempFilter;                            break;                        }                    case '|':                        {                            filter = filter | tempFilter;                            break;                        }                }            }            filter = Builders<BsonDocument>.Filter.Empty & (filter);        }        return filter ?? Builders<BsonDocument>.Filter.Empty;    }    /// <summary>    /// 将查询因子转换成Mongodb的Filter    /// </summary>    /// <param name="queryFactor"></param>    /// <returns></returns>    private FilterDefinition<BsonDocument> QueryFactorToMogodbFilter(QueryFactor queryFactor)    {        /// <summary>        /// 比较类型,支持的类型有:        /// eq:等于,        /// ne:不等于        /// gt:大于        /// lt:小于        /// gte:大于等于        /// lte:小于等于        /// in:范围查询        /// like:模糊查询        /// </summary>        if (queryFactor == null) return Builders<BsonDocument>.Filter.Empty;        FilterDefinition<BsonDocument> filter = null;        switch (queryFactor.QueryType.ToLower())        {            case "ne":                {                    filter = Builders<BsonDocument>.Filter.Ne(queryFactor.Key, queryFactor.Value);                    break;                }            case "gt":                {                    filter = Builders<BsonDocument>.Filter.Gt(queryFactor.Key, queryFactor.Value);                    break;                }            case "gte":                {                    filter = Builders<BsonDocument>.Filter.Gte(queryFactor.Key, queryFactor.Value);                    break;                }            case "lt":                {                    filter = Builders<BsonDocument>.Filter.Lt(queryFactor.Key, queryFactor.Value);                    break;                }            case "lte":                {                    filter = Builders<BsonDocument>.Filter.Lte(queryFactor.Key, queryFactor.Value);                    break;                }            case "in":                {                    filter = Builders<BsonDocument>.Filter.In(queryFactor.Key, JsonConvert.DeserializeObject<IList<String>>(JsonConvert.SerializeObject(queryFactor.Value)));                    break;                }            case "like":                {                    //filter = filter & Builders<BsonDocument>.Filter.Regex(queryFactor.Key, new BsonRegularExpression(new Regex(Regex.Escape(queryFactor.Value.ToString()), RegexOptions.IgnoreCase)));                    filter = Builders<BsonDocument>.Filter.Regex(queryFactor.Key, new BsonRegularExpression(new Regex(".*" + Regex.Escape(queryFactor.Value.ToString()) + ".*", RegexOptions.IgnoreCase)));                    break;                }            case "eq":            default:                {                    filter = Builders<BsonDocument>.Filter.Eq(queryFactor.Key, queryFactor.Value);                    break;                }        }        return filter ?? Builders<BsonDocument>.Filter.Empty;    }}

.Net Core ORM选择之路,哪个才适合你  通用查询类封装之Mongodb篇  Snowflake(雪花算法)的JavaScript实现  【开发记录】如何在B/S项目中使用中国天气的实时天气功能   【开发记录】微信小游戏开发入门——俄罗斯方块

  具体的实现思路是这样的,就是逐个的消除表达式中的括号,直到表达式中不包含圆括号,就用上面的表达式来举个例子,((a|b)&c)|((a&b&d)|e)

  1、找到最后一个“(”,之后寻找与之匹配的“)”,处理这对圆括号中的简单表达式,这里是a&b&d,处理完之后将结果放在一个字典之中<guid,filter>,记作<1,filter1>,之后字符串变为((a|b)&c)|(1|e)

  2、参照1的顺序再次处理表达式((a|b)&c)|(1|e),这次处理1|e,字典中添加一项<2,filter2>,字符串变为((a|b)&c)|2

  3、处理a|b,字典中添加一项<3,filter3>,字符串变为(3&c)|2

  4、处理3&c,字典中添加一项<4,filter4>,字符串变为4|2

  5、至此,圆括号已不再,只是简单的表达式,这就简单了

Snowflake(雪花算法)的JavaScript实现

 

  现在好多的ID都是服务器端生成的,当然JS也可以生成GUID或者UUID之类的,但是如果想要有序……这时就想到了雪花算法,但是都知道JS中Number的最大值为Number.MAX_SAFE_INTEGER:9007199254740991。在雪花算法中,有的操作在JS中会溢出。不过还好,网上有好多BigInt的类库,例如本例使用的:http://peterolson.github.io/BigInteger.js/ ,还有就是chrome67 原生支持BigInt类型,这是个好消息……

  参考文章: 理解分布式id生成算法SnowFlake

  类库:http://peterolson.github.io/BigInteger.js/

  CDN:https://cdnjs.com/

  记录一下代码

  类库方式实现:

.Net Core ORM选择之路,哪个才适合你  通用查询类封装之Mongodb篇  Snowflake(雪花算法)的JavaScript实现  【开发记录】如何在B/S项目中使用中国天气的实时天气功能   【开发记录】微信小游戏开发入门——俄罗斯方块

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <meta http-equiv="X-UA-Compatible" content="ie=edge">    <title>Document</title></head><body>    <script src="https://cdnjs.cloudflare.com/ajax/libs/big-integer/1.6.32/BigInteger.min.js"></script>    <!-- <script src="http://peterolson.github.com/BigInteger.js/BigInteger.min.js"></script> -->    <script>        var Snowflake = /** @class */ (function() {            function Snowflake(_workerId, _dataCenterId, _sequence) {                // this.twepoch = 1288834974657;                this.twepoch = 0;                this.workerIdBits = 5;                this.dataCenterIdBits = 5;                this.maxWrokerId = -1 ^ (-1 << this.workerIdBits); // 值为:31                this.maxDataCenterId = -1 ^ (-1 << this.dataCenterIdBits); // 值为:31                this.sequenceBits = 12;                this.workerIdShift = this.sequenceBits; // 值为:12                this.dataCenterIdShift = this.sequenceBits + this.workerIdBits; // 值为:17                this.timestampLeftShift = this.sequenceBits + this.workerIdBits + this.dataCenterIdBits; // 值为:22                this.sequenceMask = -1 ^ (-1 << this.sequenceBits); // 值为:4095                this.lastTimestamp = -1;                //设置默认值,从环境变量取                this.workerId = 1;                this.dataCenterId = 1;                this.sequence = 0;                if (this.workerId > this.maxWrokerId || this.workerId < 0) {                    throw new Error('config.worker_id must max than 0 and small than maxWrokerId-[' + this.maxWrokerId + ']');                }                if (this.dataCenterId > this.maxDataCenterId || this.dataCenterId < 0) {                    throw new Error('config.data_center_id must max than 0 and small than maxDataCenterId-[' + this.maxDataCenterId + ']');                }                this.workerId = _workerId;                this.dataCenterId = _dataCenterId;                this.sequence = _sequence;            }            Snowflake.prototype.tilNextMillis = function(lastTimestamp) {                var timestamp = this.timeGen();                while (timestamp <= lastTimestamp) {                    timestamp = this.timeGen();                }                return timestamp;            };            Snowflake.prototype.timeGen = function() {                //new Date().getTime() === Date.now()                return Date.now();            };            Snowflake.prototype.nextId = function() {                var timestamp = this.timeGen();                if (timestamp < this.lastTimestamp) {                    throw new Error('Clock moved backwards. Refusing to generate id for ' +                        (this.lastTimestamp - timestamp));                }                if (this.lastTimestamp === timestamp) {                    this.sequence = (this.sequence + 1) & this.sequenceMask;                    if (this.sequence === 0) {                        timestamp = this.tilNextMillis(this.lastTimestamp);                    }                } else {                    this.sequence = 0;                }                this.lastTimestamp = timestamp;                var shiftNum = (this.dataCenterId << this.dataCenterIdShift) |                    (this.workerId << this.workerIdShift) |                    this.sequence; // dataCenterId:1,workerId:1,sequence:0  shiftNum:135168                var nfirst = new bigInt(String(timestamp - this.twepoch), 10);                nfirst = nfirst.shiftLeft(this.timestampLeftShift);                var nnextId = nfirst.or(new bigInt(String(shiftNum), 10)).toString(10);                return nnextId;            };            return Snowflake;        }());        var tempSnowflake = new Snowflake(1, 1, 0);        var tempIds = [];        console.time();        for (var i = 0; i < 10000; i++) {            var tempId = tempSnowflake.nextId();            console.log(tempId);            if (tempIds.indexOf(tempId) < 0) {                tempIds.push(tempId);            }        }        console.log(tempIds.length);        console.timeEnd();    </script></body></html>

.Net Core ORM选择之路,哪个才适合你  通用查询类封装之Mongodb篇  Snowflake(雪花算法)的JavaScript实现  【开发记录】如何在B/S项目中使用中国天气的实时天气功能   【开发记录】微信小游戏开发入门——俄罗斯方块

  原生BigInt实现:

.Net Core ORM选择之路,哪个才适合你  通用查询类封装之Mongodb篇  Snowflake(雪花算法)的JavaScript实现  【开发记录】如何在B/S项目中使用中国天气的实时天气功能   【开发记录】微信小游戏开发入门——俄罗斯方块

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <meta http-equiv="X-UA-Compatible" content="ie=edge">    <title>Document</title></head><body>    <script>        var Snowflake = /** @class */ (function() {            function Snowflake(_workerId, _dataCenterId, _sequence) {                this.twepoch = 1288834974657n;                //this.twepoch = 0n;                this.workerIdBits = 5n;                this.dataCenterIdBits = 5n;                this.maxWrokerId = -1n ^ (-1n << this.workerIdBits); // 值为:31                this.maxDataCenterId = -1n ^ (-1n << this.dataCenterIdBits); // 值为:31                this.sequenceBits = 12n;                this.workerIdShift = this.sequenceBits; // 值为:12                this.dataCenterIdShift = this.sequenceBits + this.workerIdBits; // 值为:17                this.timestampLeftShift = this.sequenceBits + this.workerIdBits + this.dataCenterIdBits; // 值为:22                this.sequenceMask = -1n ^ (-1n << this.sequenceBits); // 值为:4095                this.lastTimestamp = -1n;                //设置默认值,从环境变量取                this.workerId = 1n;                this.dataCenterId = 1n;                this.sequence = 0n;                if (this.workerId > this.maxWrokerId || this.workerId < 0) {                    throw new Error('_workerId must max than 0 and small than maxWrokerId-[' + this.maxWrokerId + ']');                }                if (this.dataCenterId > this.maxDataCenterId || this.dataCenterId < 0) {                    throw new Error('_dataCenterId must max than 0 and small than maxDataCenterId-[' + this.maxDataCenterId + ']');                }                this.workerId = BigInt(_workerId);                this.dataCenterId = BigInt(_dataCenterId);                this.sequence = BigInt(_sequence);            }            Snowflake.prototype.tilNextMillis = function(lastTimestamp) {                var timestamp = this.timeGen();                while (timestamp <= lastTimestamp) {                    timestamp = this.timeGen();                }                return BigInt(timestamp);            };            Snowflake.prototype.timeGen = function() {                return BigInt(Date.now());            };            Snowflake.prototype.nextId = function() {                var timestamp = this.timeGen();                if (timestamp < this.lastTimestamp) {                    throw new Error('Clock moved backwards. Refusing to generate id for ' +                        (this.lastTimestamp - timestamp));                }                if (this.lastTimestamp === timestamp) {                    this.sequence = (this.sequence + 1n) & this.sequenceMask;                    if (this.sequence === 0n) {                        timestamp = this.tilNextMillis(this.lastTimestamp);                    }                } else {                    this.sequence = 0n;                }                this.lastTimestamp = timestamp;                return ((timestamp - this.twepoch) << this.timestampLeftShift) |                    (this.dataCenterId << this.dataCenterIdShift) |                    (this.workerId << this.workerIdShift) |                    this.sequence;            };            return Snowflake;        }());        console.time();        var tempSnowflake = new Snowflake(1n, 1n, 0n);        var tempIds = [];        for (var i = 0; i < 10000; i++) {            var tempId = tempSnowflake.nextId();            console.log(tempId);            if (tempIds.indexOf(tempId) < 0) {                tempIds.push(tempId);            }        }        console.log(tempIds.length);        console.timeEnd();    </script></body></html>

.Net Core ORM选择之路,哪个才适合你  通用查询类封装之Mongodb篇  Snowflake(雪花算法)的JavaScript实现  【开发记录】如何在B/S项目中使用中国天气的实时天气功能   【开发记录】微信小游戏开发入门——俄罗斯方块

  好像原生效果更好一些,到此结束。

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,084
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,559
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,408
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,181
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,818
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,901