.NET ORM FreeSql 第一个正式版本发布 v1.0.0
一、简介
FreeSql 是 .NET 平台下的对象关系映射技术(O/RM),支持 .NetCore 2.1+ 或 .NetFramework 4.0+ 或 Xamarin。
从 0.0.1 发布到今历时整整一年的迭代更新,现在终于敢发布第一个正式版。
本文内容从简,介绍项目的主要功能框架,以及暂时能想到的可能比较有说服力的特性。
二、项目统计
主仓库解决方案共计项目:29个
单元测试:3510个
Code Issues:168个
文档Wiki:43个
Stars:1140
Forks:236
Commits:690次
Nuget主包下载量:86,568次
开源地址:https://github.com/2881099/FreeSql
三、功能结构
支持 CodeFirst 迁移,哪怕使用 Access 数据库也支持;
支持 DbFirst 从数据库导入实体类;
支持 深入的类型映射,比如pgsql的数组类型;
支持 丰富的表达式函数,以及灵活的自定义解析;
支持 导航属性一对多、多对多贪婪加载,以及延时加载;
支持 读写分离、分表分库,租户设计,过滤器,乐观锁,悲观锁;
支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite/达梦数据库/Access;
四、CodeFirst/DbFirst
一切皆 CodeFirst,所有功能都是由实体类型,到表操作的过程。CodeFirst 【自动迁移】只需要一行代码:
using FreeSql;
static IFreeSql fsql = new FreeSqlBuilder()
.UseConnectionString(DataType.Sqlite,
@"Data Source=|DataDirectory|\document.db;Pooling=true;Max Pool Size=10")
.UseAutoSyncStructure(true) //自动同步实体结构到数据库
.Build();
在开发过程中,表结构会自动创建、或改变(不丢数据),取决于实体类的变化。
CodeFirst 提供功能丰富的特性ColumnAttribute,定义实体与表间的映射,并且支持 FluentApi 方式。如果不喜欢 ColumnAttribute 这个名字,还可以通过 AOP 设置换为 MyColumnAttribute。
using FreeSql.DataAnnotations;
class Song {
[Column(IsIdentity = true)]
public int Id { get; set; }
public string Title { get; set; }
public string Url { get; set; }
public DateTime CreateTime { get; set; }
}
DbFirst 数据表先行,许多哥们使用动软、T4模板生成实体类代码。自已处理每种数据库的字段类型,和 csharp 类型对应,比较麻烦,各大 ORM 可能还不通用。
我们提供命令行工具生成实体类,dotnet-tools,对就是它。。非常好用的工具,没有之一。
C:\Users\28810>dotnet tool install -g freesql.generator
可使用以下命令调用工具: FreeSql.Generator
已成功安装工具“freesql.generator”(版本“1.0.0”)。
C:\Users\28810>freesql.generator
____ ____ __
/ __/ ____ ___ ___ / __/ ___ _ / /
/ _/ / __// -_)/ -_) _\ \ / _ `/ / /
/_/ /_/ \__/ \__/ /___/ \_, / /_/
/_/
# Github # https://github.com/2881099/FreeSql v1.0.0
使用 FreeSql 快速生成数据库的实体类
更新工具:dotnet tool update -g FreeSql.Generator
# 快速开始 #
> FreeSql.Generator -Razor 1 -NameOptions 0,0,0,0 -NameSpace MyProject -DB "MySql,Data Source=127.0.0.1;..."
-Razor 1 * 选择模板:实体类+特性
-Razor 2 * 选择模板:实体类+特性+导航属性
-Razor "d:\diy.cshtml" * 自定义模板文件
-NameOptions * 总共4个布尔值,分别对应:
# 首字母大写
# 首字母大写,其他小写
# 全部小写
# 下划线转驼峰
-NameSpace * 命名空间
-DB "MySql,Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=数据库;Charset=utf8;SslMode=none;Max pool size=2"
-DB "SqlServer,Data Source=.;Integrated Security=True;Initial Catalog=数据库;Pooling=true;Max Pool Size=2"
-DB "PostgreSQL,Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=数据库;Pooling=true;Maximum Pool Size=2"
-DB "Oracle,user id=user1;password=123456;data source=//127.0.0.1:1521/XE;Pooling=true;Max Pool Size=2"
-DB "OdbcDameng,Driver={DM8 ODBC DRIVER};Server=127.0.0.1:5236;Persist Security Info=False;Trusted_Connection=Yes;UID=USER1;PWD=123456789;Max pool size=2"
OdbcDameng 是国产达梦数据库,需要使用 ODBC 连接
-Filter Table+View+StoreProcedure
默认生成:表+视图+存储过程
如果不想生成视图和存储过程 -Fitler View+StoreProcedure
-FileName 文件名,默认:{name}.cs
-Output 保存路径,默认为当前 shell 所在目录
推荐在实体类目录创建 gen.bat,双击它重新所有实体类
它基于 Razor 模板生成,支持自定义模板生成,意味着它远不止可以生成实体类,甚至是 IRepository 或者。。。
五、导航属性
从一开始就着重导航对象的设计,支持一对多、多对多、父子关系、一对一、多对一,不夸张的说目前对导航属性处理最流弊,最容易上手的 ORM。在多表查询的表达式使用上非常便利,如下:
fsql.Select<Catetory>()
.Where(a => a.Parent.Parent.Name == "粤语")
可以使用导航属性一直这样点下去。。。
级联保存,级联查询功能也必不可少,如下查询多对多:
fsql.Select<Song>()
.IncludeMany(a => a.Tags)
.ToList();
上面的代码,如果只返回 Tags 前 5条记录,也是支持的 .IncludeMany(a => a.Tags.Take(5))
对性能有追求,还可以指定 Tags 只查询部分字段
关于 IncludeMany 不便再这过多展开介绍。。。(其实还有黑科技!)
哦,还有 FreeSql.AdminLTE 扩展包,它不属于主仓库项目,最大化利用导航属性完成通用的 CURD 后台管理功能。
流弊哒哒~~~~
六、仓储模式
仓储工作单元目前是当下的流行风,在比较早的时候大约0.2版本发布了第一个仓储版本,当时参考了大量的项目设计,最终选用 abp vnext 的 IRepository 设计接口,实现通用仓储类功能。
也就是说,使用 FreeSql.Repository 你不必再自己写那些繁琐的 CURD 重复的仓储功能,不用再头疼仓储类的接口方法定义。定义标准比写代码难多了,abp vnext 的 IRepository 目前是见过最好的,木有之一!!
仓储模式都在操作实体对象,无论是更新还是删除,都是传对象。。。传传传。。。
问题1、传对象更新,意味着更新所有字段?
不会的,我们的仓储实现拥有状态管理机制,从对象查询出来的时候已经记录了拍照,当调用更新方法的时候会与之对比,计算出变化的字段,只更新变化的字段!
var repo = fsql.GetRepository<Song>();
var item = repo.Where(a => a.Id == 1).First();
item.Title = "原谅我今天";
repo.Update(item);
提示:支持乐观锁、悲观锁
问题2、状态管理是否影响性能?
不完全,因为状态管理设计在仓储实现之上,我们最原始的 IFreeSql 没有这个功能(仓储算是一种扩展包吧,但是仓储又非常有效)。仓储即用即销毁,擅用它的对比功能更新对象,不滥用没有性能问题。
有了仓储怎么会没有 UnitOfWork 呢,UnitOfWork 目前以事务的方式做了默认实现,并且它拥有实体变化跟踪记录。
七、性能
1、插入测试(52个字段)
测试结果,是在相同操作系统下进行的,并且都有预热
18W 解释:插入18万行记录,表格中的数字是执行时间(单位ms)
Oracle 插入性能不用怀疑,可能安装学生版限制较大
提醒:开源数据库测试结果比较有意义,商业数据库版本之间性能可能有较大差距
2、插入测试(10个字段)
提示:已经支持了 SqlServer 数据库的 SqlBulkCopy 功能、以及 PostgreSQL 数据库的 Copy 功能
八、拉姆达
非常特色的功能之一,深入细化函数解析,所支持的类型基本都可以使用对应的表达式函数,例如 日期、字符串、IN查询、数组(PostgreSQL的数组)、字典(PostgreSQL HStore)等等。
1、In查询
var t1 = fsql.Select<T>()
.Where(a => new[] { 1, 2, 3 }.Contains(a.Id))
.ToSql();
//SELECT .. FROM ..
//WHERE (a.`Id` in (1,2,3))
已优化,防止 where in 元素多过的 SQL 错误,如:
[Err] ORA-01795: maximum number of expressions in a list a 1000
原来:where id in (1…1333)
现在:where id in (1…500) or id in (501…1000) or id in (1001…1333)
2、In查询(多列)
//元组集合
vae lst = new List<(Guid, DateTime)>();
lst.Add((Guid.NewGuid(), DateTime.Now));
lst.Add((Guid.NewGuid(), DateTime.Now));
lst.Add((Guid.NewGuid(), DateTime.Now));
fsql.Select<T>()
.Where(a => lst.Contains(a.Id, a.ct1))
.ToSql();
//SELECT .. FROM ..
//WHERE (a."Id" = '685ee1f6-bdf6-4719-a291-c709b8a1378f' AND a."ct1" = '2019-12-07 23:55:27' OR
//a."Id" = '5ecd838a-06a0-4c81-be43-1e77633b7404' AND a."ct1" = '2019-12-07 23:55:27' OR
//a."Id" = 'b8b366f3-1c03-4547-9c96-d362dd5cae6a' AND a."ct1" = '2019-12-07 23:55:27')
3、自定义函数
默认已经支持了很丰富的函数解析,如果不够再自己定义:
[ExpressionCall]
public static class DbFunc
{
//必要定义 static + ThreadLocal
static ThreadLocal<ExpressionCallContext> context = new ThreadLocal<ExpressionCallContext>();
public static DateTime FormatDateTime(this DateTime that, string arg1)
{
var up = context.Value;
if (up.DataType == FreeSql.DataType.Sqlite) //重写内容
context.Value.Result = $"date_format({up.ParsedContent["that"]}, {up.ParsedContent["arg1"]})";
return that;
}
}
fsql.Select<T>().ToSql(a => a.CreateTime.FormatDateTime("yyyy-MM-dd"));
//SELECT date_format(a."CreateTime", 'yyyy-MM-dd') as1
//FROM "T" a
提示:SqlServer nvarchar/varchar 已兼容表达式解析,分别解析为:N’’ 和 ‘’,优化索引执行计划
九、骚操作
1、代码注释 -> 迁移到数据库
CodeFirst 支持将 c# 代码内的注释,迁移至数据库的备注。先决条件:
实体类所在程序集,需要开启 xml 文档功能;
xml 文件必须与程序集同目录,且文件名:xxx.dll -> xxx.xml;
2、NoneParameter
可以设置不使用 参数化 执行 SQL 命令,方便开发调试,区别如下:
INSERT INTO `tb_topic`(`Title`) VALUES(?Title0)
INSERT INTO `tb_topic`(`Title`) VALUES('Title_1')
在 new FreeSqlBuilder().UseNoneParameter(true) 全局设置
在 单次 ISelect、IInsert、IDelete、IUpdate 上使用 NoneParameter() 设置单次生效
3、Dto 映射查询
用过 ProjectTo 功能吗?没用过当忽略此行。。。
有些朋友可能是先 ToList().Mapper<T>(),这样会先查询了所有字段。
Dto 映射查询支持单表/多表,这个功能可以决定只查询部分字段(不是、不是、不是先查询所有字段再到内存映射)。
规则:查找属性名,会循环内部对象 _tables(多表会增长),以 主表优先查,直到查到相同的字段。
如:A, B, C 都有 id,Dto { id, a1, a2, b1, b2 },A.id 被映射。也可以指定 id = C.id 映射。
fsql.Select<Song>().ToList(a => new DTO { xxx = a.ext })
//情况1:附加所有映射,再额外映射 ext,返回 List<DTO>
fsql.Select<Song>().ToList(a => new Song { id = a.id })
//情况2:只查询 id,返回 List<Song>
fsql.Select<Song>().ToList(a => new { id = a.id })
//情况3:只查询 id,返回 List<匿名对象>
fsql.Select<Song>().ToList(a => new DTO(a.id))
//情况4:只查询 id,返回 List<DTO>
fsql.Select<Song>().ToList(a => new DTO(a.id) { xxx = a.ext })
//情况5:查询 id, ext,返回 List<DTO>
fsql.Select<Song>().ToList(a => new Song(a.id))
//情况6:查询 id,返回 List<Song>
fsql.Select<Song>().ToList(a => new Song(a.id) { xxx = a.ext })
//情况7:查询 id, ext,返回 List<Song>
4、WhereCascade
FreeSql 擅长多表查询,遇到像isdeleted每个表都给条件的时候,挺麻烦。WhereCascade使用后生成sql时,所有表都附上这个条件。
如:
fsql.Select<t1>()
.LeftJoin<t2>(...)
.WhereCascade(x => x.IsDeleted == false)
.ToList();
得到的 SQL:
SELECT ...
FROM t1
LEFT JOIN t2 on ... AND (t2.IsDeleted = 0)
WHERE t1.IsDeleted = 0
其中的实体可附加表达式时才生效,支持子表查询。单次查询使用的表数目越多收益越大。
5、审计 CURD
如果因为某个 sql 骚操作耗时很高,没有一个相关的审计功能,排查起来可以说无从下手。
FreeSql 支持简单的类似功能:
fsql.Aop.CurdAfter = (s, e) => {
if (e.ElapsedMilliseconds > 200) {
//记录日志
//发送短信给负责人
}
};
只需要一个事件,就可以对全局起到作用。
还有一个 CurdBefore 在执行 sql 之前触发,常用于记录日志或开发调试。
6、审计属性值
实现插入/更新时统一处理某些值,比如某属性的雪花算法值、创建时间值、甚至是业务值。
fsql.Aop.AuditValue += (s, e) => {
if (e.Column.CsType == typeof(long)
&& e.Property.GetCustomAttribute<SnowflakeAttribute>(false) != null
&& e.Value?.ToString() == 0)
e.Value = new Snowflake().GetId();
};
class Order {
[Snowflake]
public long Id { get; set; }
//...
}
当属性的类型是 long,并且标记了 [Snowflake],并且当前值是 0,那么在插入/更新时它的值将设置为雪花id值。
说明:SnowflakeAttribute 是使用者您来定义,new Snowflake().GetId() 也是由使用者您来实现
如果命名规范,可以在 aop 里判断,if (e.Property.Name == “createtime”) e.Value = DateTime.Now;
还有。。还有很多骚操作。。不便在此展开。。。
十、展望 2020
2019 年支持了主流的数据库:
SqlServer 2000-2019,支持 row_number/offset fetch next 分页自动版本选择适配,以及其他语法的差异适配,提供 ado.net 与 odbc 两种实现方式;
PostgreSQL 9.4-12,完成了版本间部分差异适配,提供 ado.net 与 odbc 两种实现方式;
MySql 5.5、Mariadb,提供 Oracle 官方驱动、与 MySqlConnector 社区驱动,还有 odbc 实现方式;
Oracle 11+,提供 ado.net 与 odbc 两种实现方式;
Sqlite,兼容了 .net core / .net framework / xamarin 平台适配,支持 CodeFirst 开发模式,一个字爽!!!
MsAccess 2003-2007,提供 oledb 实现方式,支持 CodeFirst 开发模式;
达梦,提供 odbc 的实现方式,并且支持 DbFirst 和 CodeFirst 两种开发模式;
2020 年支持国产是重点,重心,重要的工作内容,南大通用将是下一个目标,并且已经在进行中了。
开源地址:https://github.com/2881099/FreeSql
写到最后面,感谢这一年来与 FreeSql 一直陪伴的兄弟朋友们。
原文链接:https://blog.csdn.net/dotnetCore/article/details/103704647
.NET ORM FreeSql 第一个正式版本发布 v1.0.0相关推荐
- 十年来第一个正式版本 | Kali Linux 2020 发布后我们该怎么渗透?
2020年Kali Linux推出了十年来的第一个正式版本--Kali Linux 2020.1 关于这个版本新特性的简短总结: 默认用户为非root用户 独立的Kali安装镜像 无需root的Kal ...
- Linux Deepin 12.12 正式版本发布--焕然一新,即可惊艳!
Linux Deepin 12.12 正式版本发布 Linux Deepin 12.12 正式版经过团队历时一年的精心打造,携带着 Linux Deepin 家族最新应用软件和全新 Linux 平台桌 ...
- 传阿里云盘将开启扩容收费测试:200GB售价 108元/年;偷车贼使用苹果 AirTag 追踪想要盗走的高档汽车;Visual Studio 2022和 .NET 6正式版本发布|极客头条
一分钟速览新闻点! 阿里张勇发内部信:武卫不再担任阿里巴巴集团 CFO 传阿里云盘将开启扩容收费测试:200GB 售价 108 元/年 元宇宙领域出现最新招标!中国电信子公司拟采购"元宇宙数 ...
- Spring Cloud Alibaba 发布第一个正式版本,顺利完成孵化!
点击蓝色"程序猿DD"关注我 回复"资源"获取独家整理的学习资料! 相信大家对上周的 <来自 Spring Cloud 官方的消息,Spring Clou ...
- Putdb WebBuilder 6.5 正式版本发布
2012年9月,WebBuilder 6.5 正式版本终于发布.新版本的 WebBuilder 使用了多项最新的技术,使开发 Web 应用的开发更快捷和简单. WebBuilder是一款跨平台.数据库 ...
- 开源运维平台V3 正式版本发布
开源运维平台Spug 经过15个Bata版本,终于在2021年12月24日发布了v3.0.2 Release正式版本.这次由于相对2.x版本前端框架做了升级,功能也做了一些改动,所以v3版本发布后,一 ...
- postgresql立式版本下载_PostgreSQL 12.0 正式版本发布
2019-10-03,PostgreSQL全球开发组今天宣布,世界上功能最为强大的开源数据库发布PostgreSQL 12版本发布. PostgreSQL 12版在各方面都得到了加强,包括显著地提升查 ...
- 以太坊2.0客户端Lighthouse发布v1.3.0版本,为高优先级建议立即更新
官方消息,以太坊2.0客户端Lighthouse开发团队Sigma Prime表示,发布Lighthouse v1.3.0版本.该版本包括对信标链节点的重要错误修复,应将其视为所有质押者的高优先级,应 ...
- ceph 版本升级_Ceph V10.2.0 Jewel正式版本发布
本文由Ceph中国社区-半天河翻译,Devin校稿 英文出处:官网release-notes 欢迎加入翻译组 此次主版本的更新将是下一个长期稳定发行版的基础版本.在Infernalis(9.2.X)版 ...
最新文章
- Fiddler 抓取eclipse中的请求
- leetcode算法题--删除链表的节点
- 抽象SQL查询:SQL-MAP技术的使用
- 关于box-shadow属性的一点心得
- Django后端编辑图片提取主要颜色API
- 手机apk签名工具安卓版_小飞鱼APK签名工具使用方法
- 提交数据网页设计_数据化时代,爬虫工程师才是真正“扛把子”
- python使用-Python 应该怎么去练习和使用?
- RC充放电网络的定量计算
- 代理模式(Proxy) 静态
- 拓端tecdat|R语言风险价值:ARIMA,GARCH模型,Delta-normal法滚动估计,预测VaR(Value at Risk)和回测分析花旗公司股票时间序列数据
- 液压与气压传动(机电)_简要问答_复习笔记
- php 三消算法,三消游戏关卡设计教程(初级篇)——基本地形设计
- incaseformat病毒解决方法
- 单机魔域显示服务器未启动,魔域单机版_开始游戏
- safari浏览器找不到服务器怎么办,safari打不开网页因为服务器已停止响应解决方法...
- 2019年最值得学习的编程语言TOP5
- 做销售如何有效地维护好与客户的关系
- 移动端 懒加载、下拉刷新、上拉加载
- WPF 第三方控件主题库
热门文章
- 超棒的在线Bootstrap主题编辑工具 - lollytin
- JS中数组Array的用法{转载}
- 用回溯法找出n个自然数中取r个数的全排列
- IE6下z-index犯癫不起作用bug的初步研究
- (译)如何使用cocos2d制作基于tile地图的游戏教程:第一部分
- 基于MapWinGis的开发探索(三)--改善缩放、渲染、显示文本
- easyui关机图标_如何在Windows 10中创建关机图标
- 手机主题随手机壳改变_无线充电可以与手机壳一起使用吗?
- 十月cms_微软十月更新失败使整个PC行业陷入困境
- web 后台返回json格式数据的方式(status 406)