长春免费网站制作百度网盘app下载安装电脑版
news/
2025/9/23 20:37:48/
文章来源:
长春免费网站制作,百度网盘app下载安装电脑版,专业的高密网站建设,如何网站网站做代理写在开头FreeSql 是 .NET 开源生态下的 ORM 轮子#xff0c;转眼快两年了#xff0c;说真的开源不容易#xff08;只有经历过才明白#xff09;。今天带点干货和湿货给大家#xff0c;先说下湿货。认识我的人#xff0c;知道 CSRedisCore 是我写的另外一个开源组件#… 写在开头FreeSql 是 .NET 开源生态下的 ORM 轮子转眼快两年了说真的开源不容易只有经历过才明白。今天带点干货和湿货给大家先说下湿货。认识我的人知道 CSRedisCore 是我写的另外一个开源组件这个项目是 2016 年从 ctstone/csredis 项目 clone 到自己工作的项目中修改源码经过一年多生产考验于 2017 年发布开源 https://github.com/2881099/csredisctstone/csredis 项目于 2014 年停止了更新到我手里完善的功能如下连接池哨兵高可用集群redis 2.8 以上的版本命令补充包括 Geo、Stream通讯协议 bug 修复暂时想到的只有这些之后可能再补充。FreeSql 文章标题为什么要来说 csredis这两年的时间里 95% 精力都用在了 FreeSql 上面 5400 单元测试、支持十几种数据库适配渣男辜负了 csredis 这个项目。最近一个多月开源圈子的奇葩事接二连三居然有人跑去 ctstone/csredis 原作者的 issues 告我的状这个告状的人还是 NOPI 原作者因为当初他自己不维护 NPOI .NET Core 版本了社区有好人把 .NET Core 版本测试做好了开源(dotnetcore/NPOI)告状的人很真心厉害已经成功把 nuget.org/dotnetcore.npoi 整下架了。他并没有得到满足之后开始针对整个 NCC 社区成员包括我。他去了 sqlsugar issues 发表说要找出 FreeSql 抄袭 sqlsugar 的证据他又去 fur issues 发表声援说我黑他他还去 csredis 原作者 issues 发布内容企图告我的状并不是人人都像你一样强迫要求下游项目“归档”、“制裁”试问 mysql 可以要求 mariadb 归档针对 NCC 组织还是针对我本人CSRedisCore 并不在 NCC 开源组织下几天月前我已经开始了新的 redis .NET 开源组件库的编写完全自主的看你能上哪里告状。有了这么长时间的 csredis 经验重新写一个能避免很多问题设计也会更好后面我会花大部分时间做新项目这便是今天带来的湿货敬请期待发布~入戏准备2018 年 12 月份开发 FreeSql 到现在2200 颗星500 Issues200K 包下载量。说明还是有开发者关注和喜爱只要有人关注就不会停更不修 BUG 一说。大家有兴趣可以看看更新记录看看我们的代码提交量5400 单元测试不说非常多个人觉得已经超过很多国产项目。23个月了FreeSql 还活着而且生命力顽强见下图年底发布 2.0 版本正在收集需求中欢迎前去 issues 诚意登记本文将介绍在过去的几个月完成的一些有意义的功能介绍。FreeSql 是 .Net ORM能支持 .NetFramework4.0、.NetCore、Xamarin、XAUI、Blazor、以及还有说不出来的运行平台因为代码绿色无依赖支持新平台非常简单。目前单元测试数量5400Nuget下载数量200K源码几乎每天都有提交。值得高兴的是 FreeSql 加入了 ncc 开源社区https://github.com/dotnetcore/FreeSql加入组织之后社区责任感更大需要更努力做好品质为开源社区出一份力。QQ群4336577(已满)、8578575(在线)、52508226(在线)为什么要重复造轮子FreeSql 主要优势在于易用性上基本是开箱即用在不同数据库之间切换兼容性比较好。作者花了大量的时间精力在这个项目肯请您花半小时了解下项目谢谢。FreeSql 整体的功能特性如下支持 CodeFirst 对比结构变化迁移支持 DbFirst 从数据库导入实体类支持 丰富的表达式函数自定义解析支持 批量添加、批量更新、BulkCopy支持 导航属性贪婪加载、延时加载、级联保存支持 读写分离、分表分库租户设计支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite/Firebird/达梦/神通/人大金仓/MsAccess Ado.net 实现包以及 Odbc 的专门实现包干货来了1.5.0 - 1.10.0 更新的重要功能如下一、增加 Firebird 数据库实现二、增加 人大金仓/神通 数据库的访问支持三、增加 GlobalFilter.ApplyIf 创建动态过滤器四、增加 ISelect.InsertInto 将查询转换为 INSERT INTO t1 SELECT ... FROM t2 执行插入五、增加 IncludeMany(a a.Childs).ToList(a new { a.Childs }) 指定集合属性返回六、增加 ${a.Code}_{a.Id} lambda 解析七、增加 lambda 表达式树解析子查询 ToList string.Join() 产生 类似 group_concat 的效果八、增加 SqlExt 常用开窗函数的自定义表达式解析九、增加 ISelect/IInsert/IUpdate/IDelete CommandTimeout 方法设置命令超时十、完善 WhereDynamicFilter 动态过滤查询十一、增加 BeginEdit/EndEdit 批量编辑数据的功能十二、增加 父子表树表递归查询、删除功能FreeSql 使用非常简单只需要定义一个 IFreeSql 对象即可static IFreeSql fsql new FreeSql.FreeSqlBuilder().UseConnectionString(FreeSql.DataType.MySql, connectionString).UseAutoSyncStructure(true) //自动同步实体结构到数据库.Build(); //请务必定义成 Singleton 单例模式
增加 Firebird 数据库实现它的体积比前辈Interbase缩小了几十倍但功能并无阉割。为了体现Firebird短小精悍的特色开发小组在增加了超级服务器版本之后又增加了嵌入版本最新版本为2.0。Firebird的嵌入版有如下特色1、数据库文件与Firebird网络版本完全兼容差别仅在于连接方式不同可以实现零成本迁移。 2、数据库文件仅受操作系统的限制且支持将一个数据库分割成不同文件突破了操作系统最大文件的限制提高了IO吞吐量。 3、完全支持SQL92标准支持大部分SQL-99标准功能。 4、丰富的开发工具支持绝大部分基于Interbase的组件可以直接使用于Firebird。 5、支持事务、存储过程、触发器等关系数据库的所有特性。 6、可自己编写扩展函数(UDF)。 7、firebird其实并不是纯粹的嵌入式数据库embed版只是其众多版本中的一个。不过做的也很小把几个dll加起来才不到5M但是它支持绝大部份SQL92与SQL99标准嵌入式等于无需安装的本地数据库欢迎体验~~增加 人大金仓/神通 数据库的访问支持天津神舟通用数据技术有限公司简称“神舟通用公司”隶属于中国航天科技集团CASC。是国内从事数据库、大数据解决方案和数据挖掘分析产品研发的专业公司。公司获得了国家核高基科技重大专项重点支持是核高基专项的牵头承担单位。自1993年在航天科技集团开展数据库研发以来神通数据库已历经27年的发展历程。公司核心产品主要包括神通关系型数据库、神通KStore海量数据管理系统、神通商业智能套件等系列产品研发和市场销售。基于产品组合可形成支持交易处理、MPP数据库集群、数据分析与处理等解决方案可满足多种应用场景需求。产品通过了国家保密局涉密信息系统、公安部等保四级、军B 级等安全评测和认证。北京人大金仓信息技术股份有限公司以下简称“人大金仓”是具有自主知识产权的国产数据管理软件与服务提供商。人大金仓由中国人民大学一批最早在国内开展数据库教学、科研、开发的专家于1999年发起创立先后承担了国家“863”、“核高基”等重大专项研发出了具有国际先进水平的大型通用数据库产品。2018年人大金仓申报的“数据库管理系统核心技术的创新与金仓数据库产业化”项目荣获2018年度国家科学技术进步二等奖产学研的融合进一步助力国家信息化建设。随着华为、中兴事务国产数据库市场相信是未来是趋势走向纵观 .net core 整个圈子对国产神舟通用、人大金仓数据库的支持几乎为 0今天 FreeSql ORM 可以使用 CodeFirst/DbFirst 两种模式进行开发。并且声称FreeSql 对各数据库没有亲儿子一说除了 MsAcces 其他全部是亲儿子在功能提供方面一碗水端平。众所周知 EFCore for oracle 问题多并且现在才刚刚更新到 3.x在这样的背景下一个国产数据库更不能指望谁实现好用的 EFCore。目前看来除了 EFCore for sqlserver 我们没把握完全占优势起码在其他数据库肯定是我们更接地气。使用 FreeSql 访问人大金仓/神通 数据库只需要修改代码如下即可static IFreeSql fsql new FreeSql.FreeSqlBuilder().UseConnectionString(FreeSql.DataType.ShenTong, connectionString) //修改 DataType 设置切换数据库.UseAutoSyncStructure(true) //自动同步实体结构到数据库.Build(); //请务必定义成 Singleton 单例模式
增加 GlobalFilter.ApplyIf 创建动态过滤器FreeSql 使用全局过滤器非常简单我们的过滤器支持多表查询、子查询只需要设置一次public static AsyncLocalGuid TenantId { get; set; } new AsyncLocalGuid();fsql.GlobalFilter.ApplyISoftDelete(name1, a a.IsDeleted false).ApplyIfITenant(tenant, () TenantId.Value ! Guid.Empty, a a.TenantId TenantId.Value);
上面增加了两个过滤器tenant 第二个参数正是增加的功能当委托条件成立时才会附加过滤器。增加 ISelect.InsertInto 将查询转换为 INSERT INTO t1 SELECT ... FROM t2 执行插入int affrows fsql.SelectTopic().Limit(10).InsertInto(null, a new Topic2{Title a.Title});
INSERT INTO Topic2(Title, Clicks, CreateTime)
SELECT a.Title, 0, 0001-01-01 00:00:00
FROM Topic a
limit 10
注意因为 Clicks、CreateTime 没有被选择所以使用目标实体属性 [Column(InsertValueSql xx)] 设置的值或者使用目标实体属性的 c# 默认值。又一次完善了批量操作数据的功能之前已经有的功能如下fsql.InsertOrUpdate 相当于 Merge Into/on duplicate key updateDatabaseFeaturesDatabaseFeaturesMySqlon duplicate key update达梦merge intoPostgreSQLon conflict do update人大金仓on conflict do updateSqlServermerge into神通merge intoOraclemerge intoMsAccess不支持Sqlitereplace intoFirebirdmerge intofsql.Insert(数组).ExecuteAffrows() 相当于批量插入var t2 fsql.Insert(items).ExecuteAffrows();
//INSERT INTO Topic(Clicks, Title, CreateTime)
//VALUES(?Clicks0, ?Title0, ?CreateTime0), (?Clicks1, ?Title1, ?CreateTime1),
//(?Clicks2, ?Title2, ?CreateTime2), (?Clicks3, ?Title3, ?CreateTime3),
//(?Clicks4, ?Title4, ?CreateTime4), (?Clicks5, ?Title5, ?CreateTime5),
//(?Clicks6, ?Title6, ?CreateTime6), (?Clicks7, ?Title7, ?CreateTime7),
//(?Clicks8, ?Title8, ?CreateTime8), (?Clicks9, ?Title9, ?CreateTime9)
当插入大批量数据时内部采用分割分批执行的逻辑进行。分割规则数量参数量MySql50003000PostgreSQL50003000SqlServer10002100Oracle500999Sqlite5000999fsql.Insert(数组).ExecuteSqlBulkCopy、ExecutePgCopy、ExecuteMySqlBulkCopyfsql.UpdateT().SetSource(数组).ExecuteAffrows() 相当于批量更新增加 IncludeMany(a a.Childs).ToList(a new { a.Childs }) 指定集合属性返回这个功能实在太重要了在此之前 IncludeMany 和 ToList(指定字段) 八字不合用起来有些麻烦。现在终于解决了~~var t111 fsql.SelectTopic().IncludeMany(a a.TopicType.Photos).Where(a a.Id 100).ToList(a new{a.Id,a.TopicType.Photos,Photos2 a.TopicType.Photos});
增加 ${a.Code}_{a.Id} lambda 解析在之前查询数据的时候$ 这种语法糖神器居然不能使用在 lambda 表达式中实属遗憾。现在终于可以了如下var item fsql.GetRepositoryTopic().Insert(new Topic { Clicks 101, Title 我是中国人101, CreateTime DateTime.Parse(2020-7-5) });
var sql fsql.SelectTopic().WhereDynamic(item).ToSql(a new
{str $x{a.Id 1}z-{a.CreateTime.ToString(yyyyMM)}{a.Title}{a.Title}
});
Assert.Equal($SELECT concat(x,ifnull((a.Id 1), ),z-,ifnull(date_format(a.CreateTime,%Y%m), ),,ifnull(a.Title, ),,ifnull(a.Title, ),) as1
FROM tb_topic a
WHERE (a.Id {item.Id}), sql);
再次说明都是亲儿子并且都有对应的单元测试兄台大可放心用在不同的数据库中增加 lambda 表达式树解析子查询 ToList string.Join() 产生 类似 group_concat 的效果v1.8.0 string.Join ToList 实现将子查询的多行结果拼接为一个字符串如1,2,3,4fsql.SelectTopic().ToList(a new {id a.Id,concat string.Join(,, fsql.SelectStringJoin01().ToList(b b.Id))
});
//SELECT a.Id, (SELECT group_concat(b.Id separator ,)
// FROM StringJoin01 b)
//FROM Topic a
该语法在不同数据库都作了相应的 SQL 翻译。增加 SqlExt 常用的自定义表达式树解析SqlExt.cs 定义了一些常用的表达式树解析如下fsql.SelectT1, T2().InnerJoin((a, b) b.Id a.Id).ToList((a, b) new{Id a.Id,EdiId b.Id,over1 SqlExt.Rank().Over().OrderBy(a.Id).OrderByDescending(b.EdiId).ToValue(),case1 SqlExt.Case().When(a.Id 1, 10).When(a.Id 2, 11).When(a.Id 3, 12).When(a.Id 4, 13).When(a.Id 5, SqlExt.Case().When(b.Id 1, 10000).Else(999).End()).End(), //这里因为复杂才这样一般使用三元表达式即可a.Id 1 ? 10 : 11groupct1 SqlExt.GroupConcat(a.Id).Distinct().OrderBy(b.EdiId).Separator(_).ToValue()});
本功能利用 FreeSql 自定义解析实现常用表达式树解析欢迎 PR 补充增加 ISelect/IInsert/IUpdate/IDelete CommandTimeout 方法设置命令超时现在每条 crud 都可以设置命令执行的超时值如下fsql.Insertitems).CommandTimeout(60).ExecuteAffrows();fsql.DeleteT().Where(...).CommandTimeout(60).ExecuteAffrows();fsql.UpdateT().Set(a a.Clicks 1).Where(...).CommandTimeout(60).ExecuteAffrows();fsql.SelectT().Where(...).CommandTimeout(60).ToList();
完善 WhereDynamicFilter 动态过滤查询是否见过这样的高级查询功能WhereDynamicFilter 在后端可以轻松完成这件事情前端根据 UI 组装好对应的 json 字符串传给后端就行如下DynamicFilterInfo dyfilter JsonConvert.DeserializeObjectDynamicFilterInfo(
{Logic : Or,Filters :[{Field : Code, Operator : NotContains, Value : val1, Filters : [{ Field : Name, Operator : NotStartsWith, Value : val2 }]},{Field : Parent.Code, Operator : Equals, Value : val11,Filters : [{ Field : Parent.Name, Operator : Contains, Value : val22 }]}]
});
fsql.SelectVM_District_Parent().WhereDynamicFilter(dyfilter).ToList();
//SELECT a.Code, a.Name, a.ParentCode, a__Parent.Code as4, a__Parent.Name as5, a__Parent.ParentCode as6
//FROM D_District a
//LEFT JOIN D_District a__Parent ON a__Parent.Code a.ParentCode
//WHERE (not((a.Code) LIKE %val1%) AND not((a.Name) LIKE val2%) OR a__Parent.Code val11 AND (a__Parent.Name) LIKE %val22%)
ISelect.WhereDynamicFilter 方法实现动态过滤条件与前端交互支持的操作符Contains/StartsWith/EndsWith/NotContains/NotStartsWith/NotEndsWith包含/不包含like %xx%或者 like xx%或者 like %xxEqual/NotEqual等于/不等于GreaterThan/GreaterThanOrEqual大于/大于等于LessThan/LessThanOrEqual小于/小于等于Range范围查询DateRange日期范围有特殊处理 value[1] 1Any/NotAny是否符合 value 中任何一项直白的说是 SQL IN增加 BeginEdit/EndEdit 批量编辑数据的功能场景winform 加载表数据后一顿添加、修改、删除操作之后点击【保存】[Fact]
public void BeginEdit()
{fsql.DeleteBeginEdit01().Where(11).ExecuteAffrows();var repo fsql.GetRepositoryBeginEdit01();var cts new[] {new BeginEdit01 { Name 分类1 },new BeginEdit01 { Name 分类1_1 },new BeginEdit01 { Name 分类1_2 },new BeginEdit01 { Name 分类1_3 },new BeginEdit01 { Name 分类2 },new BeginEdit01 { Name 分类2_1 },new BeginEdit01 { Name 分类2_2 }}.ToList();repo.Insert(cts);repo.BeginEdit(cts); //开始对 cts 进行编辑cts.Add(new BeginEdit01 { Name 分类2_3 });cts[0].Name 123123;cts.RemoveAt(1);Assert.Equal(3, repo.EndEdit());
}
class BeginEdit01
{public Guid Id { get; set; }public string Name { get; set; }
}
上面的代码 EndEdit 方法执行的时候产生 3 条 SQL 如下INSERT INTO BeginEdit01(Id, Name) VALUES(5f26bf07-6ac3-cbe8-00da-7dd74818c3a6, 分类2_3)UPDATE BeginEdit01 SET Name 123123
WHERE (Id 5f26bf00-6ac3-cbe8-00da-7dd01be76e26)DELETE FROM BeginEdit01 WHERE (Id 5f26bf00-6ac3-cbe8-00da-7dd11bcf54dc)
提醒该操作只对变量 cts 有效不是针对全表对比更新。增加 父子表树表递归查询、删除功能无限级分类父子是一种比较常用的表设计每种设计方式突出优势的同时也带来缺陷如方法1表设计中只有 parent_id 字段困扰查询麻烦本文可解决方法2表设计中冗余子级id便于查询困扰添加/更新/删除的时候需要重新计算方法3表设计中存储左右值编码困扰同上方法1设计最简单我们正是解决它设计简单使用复杂的问题。首先按照导航属性的定义定义好父子属性public class Area
{[Column(IsPrimary true)]public string Code { get; set; }public string Name { get; set; }public virtual string ParentCode { get; set; }[Navigate(nameof(ParentCode))]public Area Parent { get; set; }[Navigate(nameof(ParentCode))]public ListArea Childs { get; set; }
}
定义 Parent 属性在表达式中可以这样fsql.SelectArea().Where(a a.Parent.Parent.Parent.Name 中国).First();
定义 Childs 属性在表达式中可以这样子查询fsql.SelectArea().Where(a a.Childs.AsSelect().Any(c c.Name 北京)).First();
定义 Childs 属性还可以使用【级联保存】、【贪婪加载】 等等操作。利用级联保存添加测试数据如下fsql.DeleteArea().Where(11).ExecuteAffrows();
var repo fsql.GetRepositoryArea();
repo.DbContextOptions.EnableAddOrUpdateNavigateList true;
repo.DbContextOptions.NoneParameter true;
repo.Insert(new Area
{Code 100000,Name 中国,Childs new ListArea(new[] {new Area{Code 110000,Name 北京,Childs new ListArea(new[] {new Area{ Code110100, Name 北京市 },new Area{ Code110101, Name 东城区 },})}})
});
功能1ToTreeList配置好父子属性之后就可以这样用了var t1 fsql.SelectArea().ToTreeList();
Assert.Single(t1);
Assert.Equal(100000, t1[0].Code);
Assert.Single(t1[0].Childs);
Assert.Equal(110000, t1[0].Childs[0].Code);
Assert.Equal(2, t1[0].Childs[0].Childs.Count);
Assert.Equal(110100, t1[0].Childs[0].Childs[0].Code);
Assert.Equal(110101, t1[0].Childs[0].Childs[1].Code);
查询数据本来是平面的ToTreeList 方法将返回的平面数据在内存中加工为树型 List 返回。功能2AsTreeCte 递归删除很常见的无限级分类表功能删除树节点时把子节点也处理一下。fsql.SelectArea().Where(a a.Name 中国).AsTreeCte().ToDelete().ExecuteAffrows(); //删除 中国 下的所有记录
如果软删除fsql.SelectArea().Where(a a.Name 中国).AsTreeCte().ToUpdate().Set(a a.IsDeleted, true).ExecuteAffrows(); //软删除 中国 下的所有记录
功能3AsTreeCte 递归查询若不做数据冗余的无限级分类表设计递归查询少不了AsTreeCte 正是解决递归查询的封装方法参数说明参数描述(可选) pathSelector路径内容选择可以设置查询返回中国 - 北京 - 东城区(可选) upfalse(默认)由父级向子级的递归查询true由子级向父级的递归查询(可选) pathSeparator设置 pathSelector 的连接符默认-(可选) level设置递归层级通过测试的数据库MySql8.0、SqlServer、PostgreSQL、Oracle、Sqlite、达梦、人大金仓姿势一AsTreeCte() ToTreeListvar t2 fsql.SelectArea().Where(a a.Name 中国).AsTreeCte() //查询 中国 下的所有记录.OrderBy(a a.Code).ToTreeList(); //非必须也可以使用 ToList见姿势二
Assert.Single(t2);
Assert.Equal(100000, t2[0].Code);
Assert.Single(t2[0].Childs);
Assert.Equal(110000, t2[0].Childs[0].Code);
Assert.Equal(2, t2[0].Childs[0].Childs.Count);
Assert.Equal(110100, t2[0].Childs[0].Childs[0].Code);
Assert.Equal(110101, t2[0].Childs[0].Childs[1].Code);
// WITH as_tree_cte
// as
// (
// SELECT 0 as cte_level, a.Code, a.Name, a.ParentCode
// FROM Area a
// WHERE (a.Name 中国)// union all// SELECT wct1.cte_level 1 as cte_level, wct2.Code, wct2.Name, wct2.ParentCode
// FROM as_tree_cte wct1
// INNER JOIN Area wct2 ON wct2.ParentCode wct1.Code
// )
// SELECT a.Code, a.Name, a.ParentCode
// FROM as_tree_cte a
// ORDER BY a.Code
姿势二AsTreeCte() ToListvar t3 fsql.SelectArea().Where(a a.Name 中国).AsTreeCte().OrderBy(a a.Code).ToList();
Assert.Equal(4, t3.Count);
Assert.Equal(100000, t3[0].Code);
Assert.Equal(110000, t3[1].Code);
Assert.Equal(110100, t3[2].Code);
Assert.Equal(110101, t3[3].Code);
//执行的 SQL 与姿势一相同
姿势三AsTreeCte(pathSelector) ToList设置 pathSelector 参数后如何返回隐藏字段var t4 fsql.SelectArea().Where(a a.Name 中国).AsTreeCte(a a.Name [ a.Code ]).OrderBy(a a.Code).ToList(a new { item a, level Convert.ToInt32(a.cte_level), path a.cte_path });
Assert.Equal(4, t4.Count);
Assert.Equal(100000, t4[0].item.Code);
Assert.Equal(110000, t4[1].item.Code);
Assert.Equal(110100, t4[2].item.Code);
Assert.Equal(110101, t4[3].item.Code);
Assert.Equal(中国[100000], t4[0].path);
Assert.Equal(中国[100000] - 北京[110000], t4[1].path);
Assert.Equal(中国[100000] - 北京[110000] - 北京市[110100], t4[2].path);
Assert.Equal(中国[100000] - 北京[110000] - 东城区[110101], t4[3].path);
// WITH as_tree_cte
// as
// (
// SELECT 0 as cte_level, a.Name || [ || a.Code || ] as cte_path, a.Code, a.Name, a.ParentCode
// FROM Area a
// WHERE (a.Name 中国)// union all// SELECT wct1.cte_level 1 as cte_level, wct1.cte_path || - || wct2.Name || [ || wct2.Code || ] as cte_path, wct2.Code, wct2.Name, wct2.ParentCode
// FROM as_tree_cte wct1
// INNER JOIN Area wct2 ON wct2.ParentCode wct1.Code
// )
// SELECT a.Code as1, a.Name as2, a.ParentCode as5, a.cte_level as6, a.cte_path as7
// FROM as_tree_cte a
// ORDER BY a.Code
更多姿势...请根据代码注释进行尝试写在最后给 .NET 开源社区贡献一点力时希望作者的努力能打动到你请求正在使用的、善良的您能动一动小手指把文章转发一下让更多人知道 .NET 有这样一个好用的 ORM 存在。谢谢了FreeSql 使用最宽松的开源协议 MIT https://github.com/dotnetcore/FreeSql完全可以商用文档齐全。QQ群4336577(已满)、8578575(在线)、52508226(在线)如果你有好的 ORM 实现想法欢迎给作者留言讨论谢谢观看2.0 版本意见正在登记中https://github.com/dotnetcore/FreeSql/issues/469本文作者FreeSql CSRedis本文链接https://www.cnblogs.com/kellynic/p/13855784.html
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/913824.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!