【纯技术贴】.NETStandard FreeSql v0.0.9 功能预览
年关将至,首页技术含量文章真是越来越少,理解大家盼着放假过年,哥们我何尝不是,先给大家拜个早年。
兄弟我从11月底发了神经,开启了 ORM 功能库的开发之旅,历时两个月编码和文档整理,目前预览版本更新到 v0.0.9 仍是一个初级版本,怎奈今天把 wiki 文档更新到一半,突然想写一篇文章提前向大家介绍项目。
快过年还逼着您来了解新的技术,实在是抱歉了。介绍一下自己,有一些朋友可能知道我本人,我经常会在群里放开源项目,比如 dotnetGen、csredis 等,反感之余仍然希望可以真的帮助到有需要的人,CSRedisCore 正是本人维护的项目,本文介绍的不是它。
简单点介绍,FreeSql 是一个NETStandard ORM 功能库,采用 MIT 开源协议部署在 github。
它实现了的功能特性
- [x] CodeFirst 迁移。
- [x] DbFirst 从数据库导入实体类,支持三种模板生成器。
- [x] 采用 ExpressionTree 高性能读取数据。
- [x] 类型映射深入支持,比如pgsql的数组类型。
- [x] 支持丰富的表达式函数。
- [x] 支持导航属性查询,和延时加载。
- [x] 支持同步/异步数据库操作方法,丰富多彩的链式查询方法。
- [x] 支持事务。
- [x] 支持读写分离。
- [x] 支持多种数据库,MySql/SqlServer/PostgreSQL/Oracle/Sqlite。
快速开始
var connstr = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;" + "Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10";IFreeSql fsql = new FreeSql.FreeSqlBuilder().UseConnectionString(FreeSql.DataType.MySql, connstr).UseSlave("connectionString1", "connectionString2") //使用从数据库,支持多个.UseMonitorCommand(cmd => Console.WriteLine(cmd.CommandText), //监听SQL命令对象,在执行前(cmd, traceLog) => Console.WriteLine(traceLog)) //监听SQL命令对象,在执行后.UseLogger(null) //使用日志,不指定默认输出控制台 ILogger.UseCache(null) //使用缓存,不指定默认使用内存 IDistributedCache.UseAutoSyncStructure(true) //自动同步实体结构到数据库.UseSyncStructureToLower(true) //转小写同步结构.UseLazyLoading(true) //延时加载导航属性对象,导航属性需要声明 virtual.Build();
定义实体
可从现有数据库生成实体模型,提供 IDbFirst 生成实体模型。或者手动创建模型,基于模型创建或修改数据库,提供 ICodeFirst 同步结构的 API(甚至可以做到开发阶段自动同步)。
[Table(Name = "tb_topic")]
class Topic {[Column(IsIdentity = true, IsPrimary = true)]public int Id { get; set; }public int Clicks { get; set; }public int TestTypeInfoGuid { get; set; }public TestTypeInfo Type { get; set; }public string Title { get; set; }public DateTime CreateTime { get; set; }
}
class TestTypeInfo {public int Guid { get; set; }public int ParentId { get; set; }public TestTypeParentInfo Parent { get; set; }public string Name { get; set; }
}
class TestTypeParentInfo {public int Id { get; set; }public string Name { get; set; }
}ISelect<Topic> select => fsql.Select<Topic>();
查询
普通查询
var sql = select.Where(a => a.Id == 10).ToSql();
///SELECT ... FROM `tb_topic` a WHERE (a.`Id` = 10)sql = select.Where(a => a.Id == 10 && a.Id > 10 || a.Clicks > 100).ToSql();
///SELECT ... FROM `tb_topic` a WHERE (a.`Id` = 10 AND a.`Id` > 10 OR a.`Clicks` > 100)sql = select.Where(a => new []{1,2,3}.Contains(a.Id)).ToSql();
//SELECT ... FROM `tb_topic` a WHERE (a.`Id` in (1,2,3))
每页20条数据,查询第1页
var sql = select.Page(1, 20).ToSql();
///SELECT ... FROM `tb_topic` a LIMIT 0,20
利用导航属性联表
sql = select.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid).ToSql();
//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a__Type.`Guid`, a__Type.`ParentId`, a__Type.`Name`, a.`Title`, a.`CreateTime`
//FROM `tb_topic` a
//LEFT JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid`sql = select.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid).LeftJoin(a => a.Type.Parent.Id == a.Type.ParentId).ToSql();
//SELECT ...
//FROM `tb_topic` a
//LEFT JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid`
//LEFT JOIN `TestTypeParentInfo` a__Type__Parent ON a__Type__Parent.`Id` = a__Type.`ParentId`
子表 Exists 查询
var sql2222 = select.Where(a => select.Where(b => b.Id == a.Id).Any()).ToList();
// SELECT ... FROM `xxx` a WHERE (exists(SELECT 1 FROM `xxx` b WHERE (b.`Id` = a.`Id`)))//两级相同的子表查询
sql2222 = select.Where(a =>select.Where(b => b.Id == a.Id && select.Where(c => c.Id == b.Id).Where(d => d.Id == a.Id).Where(e => e.Id == b.Id).Offset(a.Id).Any()).Any()
).ToList();
// SELECT ... FROM `xxx` a WHERE (exists(SELECT 1 FROM `xxx` b WHERE (b.`Id` = a.`Id` AND exists(SELECT 1 FROM `xxx` c WHERE (c.`Id` = b.`Id`) AND (c.`Id` = a.`Id`) AND (c.`Id` = b.`Id`) limit 0,1)) limit 0,1))
查找今天创建的数据
select.Where(a => a.CreateTime.Date == DateTime.Now.Date).ToSql();
支持功能丰富的表达式函数解析,包括(字符串、日期、时间、数学、类型转换)等函数,方便程序员在不了解数据库函数的情况下编写代码。这是非常特色的功能之一,深入细化函数解析尽量做到满意,所支持的类型基础都可以使用对应的表达式函数,例如 日期、字符串、IN查询、数组(PostgreSQL的数组)、字典(PostgreSQL HStore)等等。
获得查询返回的数据
采用 ExpressionTree 优化读取速读,如果懂技术的你一定知道 .NETCore 技术下除了原生代码,最快就是 Emit 和 ExpressionTree。项目在初期使用的反射+缓存,虽然 .NETCore 优化了反射性能,但经过与Dapper性能测试对比之后,发现仍然有一定差距,改成 ExpresstionTree 后才与 Dapper 性能相当。FreeSql 支持的类型较多,现实 ExpressionTree 的复杂度较大,有兴趣的朋友可以翻阅源代码。
返回单条记录
Topic t1 = select.Where(a => a.Id == 1).ToOne();
FreeSql有两个约定,ToOne 永远返回 null 或 有数据的实体对象,ToList 永远返回非 null 的 List<实体类型>
返回 List
List<Topic> t1 = select.Where(a => a.Id > 0).Skip(100).Limit(200).ToList();
返回 List + 导航属性的数据
List<Topic> t2 = select.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid).ToList();
//此时会返回普通字段 + 导航对象 Type 的数据
指定字段返回
//返回一个字段
List<int> t3 = select.Where(a => a.Id > 0).Skip(100).Limit(200).ToList(a => a.Id);//返回匿名类
List<匿名类> t4 = select.Where(a => a.Id > 0).Skip(100).Limit(200).ToList(a => new { a.Id, a.Title });//返回元组
List<(int, string)> t5 = select.Where(a => a.Id > 0).Skip(100).Limit(200).ToList<(int, string)>("id, title");//返回SQL字段
List<匿名类> t6 = select.Where(a => a.Id > 0).Skip(100).Limit(200).ToList(a => new {a.Id,a.Title,cstitle = "substr(a.title, 0, 2)", //将 substr(a.title, 0, 2) 作为查询字段csnow = Convert.ToDateTime("now()"), //将 now() 作为查询字段//奇思妙想:怎么查询开窗函数的结果});//返回更为复杂的结构
List<匿名类> t7 = select.From<TestTypeInfo, TestTypeParentInfo>((s, b, c) => s.InnerJoin(a => a.TypeGuid == b.Guid).LeftJoin(a => c.Id == b.ParentId).Where(a => b.Name != "xxx")).ToList((a, b, c) => new {a.Id,a.Title,a.Type,ccc = new { a.Id, a.Title },tp = a.Type,tp2 = new {a.Id,tp2 = a.Type.Name},tp3 = new {a.Id,tp33 = new {a.Id}}});
执行SQL返回数据
class xxx {public int Id { get; set; }public string Path { get; set; }public string Title2 { get; set; }
}List<xxx> t8 = fsql.Ado.Query<xxx>("select * from song");
List<(int, string ,string)> t7 = fsql.Ado.Query<(int, string, string)>("select * from song");
List<dynamic> t9 = fsql.Ado.Query<dynamic>("select * from song");
CodeFirst
支持 CodeFirst 迁移结构至数据库,这应该是(O/RM)必须标配的一个功能。
与其他(O/RM)不同FreeSql支持更多的数据库特性,而不只是支持基础的数据类型,这既是优点也是缺点,优点是充分利用数据库特性辅助开发,缺点是切换数据库变得困难。不同程序员的理念可能不太一致,作为功能库FreeSql支持到了极致,至于是否使用是项目组技术衡量的另一个问题。
尽管多种数据库适配逻辑非常复杂,FreeSql始终秉承优化程序开发习惯的原则尽量去现实,中间碰到了一些非技术无法攻克的难题,比如数据库的自定义类型,和实体类本身就是一种冲突,为了减少使用成本,诸如此类的数据库功能没有得到支持。
除了在实体上标注特性,也支持实体以外配置
fsql.CodeFirst.ConfigEntity<TestFluenttb1>(a => {a.Name("xxdkdkdk1").SelectFilter("a.Id22 > 0");a.Property(b => b.Id).Name("Id22").IsIdentity(true);a.Property(b => b.name).DbType("varchar(100)").IsNullable(true);}).ConfigEntity<TestFluenttb2>(a => {a.Name("xxdkdkdk2").SelectFilter("a.Idx > 0");a.Property(b => b.Id).Name("Id22").IsIdentity(true);a.Property(b => b.name).DbType("varchar(100)").IsNullable(true);});
类型映射
csharp | MySql | SqlServer | PostgreSQL | Oracle | Sqlite |
---|---|---|---|---|---|
bool | bool? | bit(1) | bit | bool | number(1) | boolean |
sbyte | sbyte? | tinyint(3) | smallint | int2 | number(4) | smallint |
short | short? | smallint(6) | smallint | int2 | number(6) | smallint |
int | int? | int(11) | int | int4 | number(11) | integer |
long | long? | bigint(20) | bigint | int8 | number(21) | integer |
byte | byte? | tinyint(3) unsigned | tinyint | int2 | number(3) | int2 |
ushort | ushort? | smallint(5) unsigned | int | int4 | number(5) | unsigned |
uint | uint? | int(10) unsigned | bigint | int8 | number(10) | decimal(10,0) |
ulong | ulong? | bigint(20) unsigned | decimal(20,0) | numeric(20,0) | number(20) | decimal(21,0) |
double | double? | double | float | float8 | float(126) | double |
float | float? | float | real | float4 | float(63) | float |
decimal | decimal? | decimal(10,2) | decimal(10,2) | numeric(10,2) | number(10,2) | decimal(10,2) |
Guid | Guid? | char(36) | uniqueidentifier | uuid | char(36 CHAR) | character(36) |
TimeSpan | TimeSpan? | time | time | time | interval day(2) to second(6) | bigint |
DateTime | DateTime? | datetime | datetime | timestamp | timestamp(6) | datetime |
DateTimeOffset | DateTimeOffset? | - | - | datetimeoffset | timestamp(6) with local time zone | - |
Enum | Enum? | enum | int | int4 | number(16) | mediumint |
FlagsEnum | FlagsEnum? | set | bigint | int8 | number(32) | bigint |
byte[] | varbinary(255) | varbinary(255) | bytea | blob | blob |
string | varchar(255) | nvarchar(255) | varchar(255) | nvarchar2(255) | nvarchar(255) |
MygisPoint | point | - | - | - | - |
MygisLineString | linestring | - | - | - | - |
MygisPolygon | polygon | - | - | - | - |
MygisMultiPoint | multipoint | - | - | - | - |
MygisMultiLineString | multilinestring | - | - | - | - |
MygisMultiPolygon | multipolygon | - | - | - | - |
BitArray | - | - | varbit(64) | - | - |
NpgsqlPoint | - | - | point | - | - |
NpgsqlLine | - | - | line | - | - |
NpgsqlLSeg | - | - | lseg | - | - |
NpgsqlBox | - | - | box | - | - |
NpgsqlPath | - | - | path | - | - |
NpgsqlPolygon | - | - | polygon | - | - |
NpgsqlCircle | - | - | circle | - | - |
(IPAddress Address, int Subnet) | - | - | cidr | - | - |
IPAddress | - | - | inet | - | - |
PhysicalAddress | - | - | macaddr | - | - |
NpgsqlRange<int> | - | - | int4range | - | - |
NpgsqlRange<long> | - | - | int8range | - | - |
NpgsqlRange<decimal> | - | - | numrange | - | - |
NpgsqlRange<DateTime> | - | - | tsrange | - | - |
PostgisPoint | - | - | geometry | - | - |
PostgisLineString | - | - | geometry | - | - |
PostgisPolygon | - | - | geometry | - | - |
PostgisMultiPoint | - | - | geometry | - | - |
PostgisMultiLineString | - | - | geometry | - | - |
PostgisMultiPolygon | - | - | geometry | - | - |
PostgisGeometry | - | - | geometry | - | - |
PostgisGeometryCollection | - | - | geometry | - | - |
Dictionary<string, string> | - | - | hstore | - | - |
JToken | - | - | jsonb | - | - |
JObject | - | - | jsonb | - | - |
JArray | - | - | jsonb | - | - |
数组 | - | - | 以上所有类型都支持 | - | - |
以上类型和长度是默认值,可手工设置,如 string 属性可指定 [Column(DbType = "varchar(max)")]
DbFirst
FreeSql 同样支持 DbFirst 的开发模式,即先有数据库再有项目,这种传统的开发模式永远不会过时,特别适合老项目仍然在维护,或者数据库重构成本过高的项目。关系型数据库有许多成熟的运维和开发类配套工具,例如我们所关注的ER图工具 PowerdeSigner,使用它可以更直观的查看表之间的关系。除了FreeSql作者同时在维护超过十年的代码生成器dotnetGen项目,它是一款支持超快速开发且高度可控的解决方案,非常喜欢 DbFirst 的开发模式,因此在 FreeSql for DbFirst 功能上会有不错的支持。
DbFirst 模式开发主要提供了不同数据库的表结构查询适配,配合模板生成器现实从数据库导入模型到c#代码中。
生成器是基于 DbFirst 开发的辅助工具,适用老项目一键生成实体。生成器采用模板的方式,实现了三种生成模板:
模板名称 | 路径 | 类型映射 | 外键导航属性 | 缓存管理 | 失血 | 贫血 | 充血 |
---|---|---|---|---|---|---|---|
simple-entity | ../Templates/MySql/simple-entity | √ | X | X | √ | X | X |
simple-entity-navigation-object | ../Templates/MySql/simple-entity-navigation-object | √ | √ | X | √ | X | X |
rich-entity-navigation-object | ../Templates/MySql/rich-entity-navigation-object | √ | √ | √ | X | √ | X |
结语
项目功能与文档较多,许多细节不适合在一篇文章中展示详尽,更多的功能介绍请移步 github wiki 中心。借此文章介绍FreeSql这个国产ORM,希望能得到大家的支持。
FreeSql 口号:打造 .NETCore 最方便的 ORM!
项目地址:https://github.com/2881099/FreeSql
文档中心:https://github.com/2881099/FreeSql/wiki
最后诚心邀请您的参与加入,一起完成 FreeSql 的使命。
转载于:https://www.cnblogs.com/kellynic/p/10310484.html
【纯技术贴】.NETStandard FreeSql v0.0.9 功能预览相关推荐
- .NETStandard FreeSql v0.0.9 功能预览
年关将至,首页技术含量文章真是越来越少,理解大家盼着放假过年,哥们我何尝不是,先给大家拜个早年. 兄弟我从11月底发了神经,开启了 ORM 功能库的开发之旅,历时两个月编码和文档整理,目前预览版本更新 ...
- 清华大学计算机科学与技术vlog,院系宣传 | 计算机科学与技术系:会当0绝顶,1览众山小...
原标题:院系宣传 | 计算机科学与技术系:会当0绝顶,1览众山小 院系概况 南京大学的计算机科学研究起步于1958年.1978年,在原有的计算技术.计算数学.数理逻辑等专业基础上成立了计算机科学系,1 ...
- 纯前端下载pdf链接文件,而不是打开预览的解决方案
纯前端下载pdf链接文件,而不是打开预览的解决方案 参考文章: (1)纯前端下载pdf链接文件,而不是打开预览的解决方案 (2)https://www.cnblogs.com/jackson-yqj/ ...
- nacos配置ap_Nacos 1.0.0 功能预览
本文来自于我的个人主页:Nacos 1.0.0 功能预览,转载请保留链接 ;) Nacos 1.0.0 是正式 GA 的版本,在架构.功能和API设计上进行了全方位的重构和升级,1.0.0版本标志着N ...
- pip无法更新_TensorFlow 2.0「开发者预览版」上线,内容每日更新
TensorFlow 2.0 预览版上线了!近日,谷歌 AI 团队成员 Martin Wicke 在社交网络上向大家发布了这一最流行深度学习框架的「开发者预览版」,该版本又被称为「Nightly 版」 ...
- .NET Pet Shop 4.0案例研究预览篇
概述<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 随着.NE ...
- Silverlight 1.0 RC SDK 预览
微软公司在几周内就会发表Silverlight 1.0 RC版.其实Joe Stegman早已在其博客指出Silverlight 1.0 Beta与Silverlight 1.0 RC版的一些重大差异 ...
- 老子学不动系列:Vue 3.0 新特性预览
尤大昨天在 Vue Toronto 的主题演讲中预览了 Vue 3 .通过利用现代浏览器支持的新功能,Vue 3 将成为我们已经了解和喜爱的Vue.js 的改进版本. 我们期待的 Vue 3 将会是: ...
- MT8788 android 9.0 gsensor导致预览与拍出来的照片方向不一致
在项目中,组装好的样机(主板竖着放)与未组装的主板(水平放置)烧写的同一套代码,经测试发现,组装好的样机(主板竖着放)相机预览与照片方向不一致,未组装的主板(水平放置)相机预览与照片方向是正常的.后来 ...
最新文章
- react按需加载(getComponent优美写法),并指定输出模块名称解决缓存(getComponent与chunkFilename)...
- 不要痴迷蓝牙耳机了,出门选这个准没错,99W+人的选择
- 超酷炫!Facebook用深度学习和弱监督学习绘制全球精准道路图
- 玉林财经学校计算机及应用课程,广西玉林财经学校
- POJ 3126 Prime Path BFS搜索
- 在实际管理中学习管理
- pcb过孔与电流对照一览表_PCB设计项目能不能成功,这个因素占了30%
- 受限玻尔兹曼机(Restricted Boltzmann Machine)分析
- LinuxC高级编程——进程
- c语言能让制表符空9个字符码,C语言编程规范 – 嗨!大佟!
- 一直跳出来 visual_只练开合跳一个动作,会瘦吗?
- OD使用教程7(上)- 调试篇07|解密系列
- Web 项目中,MySQL 最新驱动下载、及配置
- Word经典技巧大全
- 小程序JSAPI预下单与回调
- ckfinder的使用及了解config.xml的配置
- 中职教计算机专业发展,中等职业教育中计算机专业教育思考
- 简洁明了的插值音频重采样算法例子 (附完整C代码)
- 信息系统项目管理师(2022年)—— 重点内容:项目人力资源管理(9)
- Ubtun16.04 配置baxter机器人
热门文章
- K8S删除某一个命名空间下所有的pod deployment statefulset命令
- Ansible搭建hadoop3.1.3高可用集群
- pythonanywhere使用:进入虚拟机及修改django项目的css样式
- 分布式锁的三种实现的对比
- 如何理解拜占庭将军问题?
- Scala算术运算符细节说明
- Linux whoami指令
- 请说明一下Spring中BeanFactory和ApplicationContext的区别是什么?
- JavaSE、JavaEE与Spring的概念和异同点剖析
- lisp 角平分线_最佳VisualLISP及VBAforAutoCAD2000程序123例 张光斌.pdf