FreeSql 开源发布快一年了,立志成为 .Net 平台方便好用的 ORM,仓库地址:https://github.com/2881099/FreeSqlhtml
随着不断的迭代更新,愈来愈稳定,也愈来愈强大。预计在一周年的时候(2020年1月1日)发布 1.0 正式版本。git
金九银十的日子过去了,在这个铜通常的月份里,鄙人作了几个重大功能,但愿对使用者开发提供更大的便利。github
如下的代码,先决定义代码以下 :sql
IFreeSql fsql = new FreeSql.FreeSqlBuilder() .UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\db1.db;Max Pool Size=10";) .UseAutoSyncStructure(true) //自动同步实体结构到数据库 .Build(); public class Blog { public Guid Id { get; set; } public string Url { get; set; } public int Rating { get; set; } }
class Dto { public Guid Id { get; set; } public string Url { get; set; } public int xxx { get; set; } } fsql.Select<Blog>().ToList<Dto>(); //SELECT Id, Url FROM Blog fsql.Select<Blog>().ToList(a => new Dto { xxx = a.Rating} ); //SELECT Id, Url, Rating as xxx FROM Blog //这样写,附加全部映射,再额外映射 xxx fsql.Select<Blog>().ToList(a => new Blog { Id = a.Id }) //这样写,只查询 id fsql.Select<Blog>().ToList(a => new { a.Id }) //这样写,只查询 id,返回匿名对象
映射支持单表/多表,是在查询数据以前映射(不是先查询全部字段再到内存映射)数据库
查找规则,查找属性名,会循环内部对象 _tables(join 查询后会增加),以 主表优先查,直到查到相同的字段。数组
如:ide
A, B, C 都有 id,Dto { id, a1, a2, b1, b2 },A.id 被映射。也能够指定 id = C.id 映射。性能
友情提醒:在 dto 能够直接映射一个导航属性单元测试
以前已经实现,有设置关系,和未设置关系 的导航集合属性联级加载。测试
有设置关系的(支持一对多、多对多):
fsql.Select<Tag>().IncludeMany(a => a.Goods).ToList();
未设置关系的,临时指定关系(只支持一对多):
fsql.Select<Goods>().IncludeMany(a => a.Comment.Where(b => b.TagId == a.Id));
只查询每项子集合的前几条数据,避免像EfCore加载全部数据致使IO性能低下(好比某商品下有2000条评论):
fsql.Select<Goods>().IncludeMany(a => a.Comment.Take(10));
上面已有的 IncludeMany 功能还不够自由灵活。
老的 IncludeMany 限制只能在 ISelect 内使用,必需要先查上级数据,解决这个问题咱们作了直接在 Dto 上作映射:
查询 Goods 商品表,分类一、分类二、分类3 各10条数据
//定义临时类,也能够是 Dto 类 class Dto { public int TypeId { get; set; } public List<Goods > GoodsList { get; set; } } var dto = new [] { 1,2,3 }.Select(a => new Dto { TypeId = a }).ToList(); dto.IncludeMany(d => d.GoodsList.Take(10).Where(gd => gd.TypeId == d.TypeId)); //执行后,dto 每一个元素.Vods 将只有 10条记录
如今 IncludeMany 再也不是 ISelect 的专利,普通的 List<T> 也能够用它来贪婪加载数据,并准确填充到内部各元素中。
老的 IncludeMany 限制只能查子表的全部字段,子表过段多过的话比较浪费 IO 性能。
新功能能够设置子集合返回部分字段,避免子集合字段过多的问题。
fsql.Select<Tag>().IncludeMany(a => a.Goods.Select(b => new Goods { Id = b.Id, Title = b.Title })); //只查询 goods 表 id, title 字段,再做填充
相信不少 ORM 解析表达式的时候处理不了这个问题,咱们以前已经解决了 99%。
这个月发现还有一余孽未清,发现问题后及时解决了,并增长单元测试代码以绝后患。
在此以前,FreeSql.DbContext 和 仓储实现,已经实现了联级保存功能,以下:
联级保存功能可实现保存对象的时候,将其【OneToMany】、【ManyToMany】导航属性集合也一并保存。
全局关闭:
fsql.SetDbContextOptions(opt => opt.EnableAddOrUpdateNavigateList = false);
局部关闭:
var repo = fsql.GetRepository<T>(); repo.DbContextOptions.EnableAddOrUpdateNavigateList = false;
保存实体的指定【多对多】导航属性,SaveManyToMany 方法实如今 BaseRepository、DbContext。
解决问题:当实体类导航数据过于复杂的时候,选择关闭联级保存的功能是明智之选,可是此时【多对多】数据保存功能写起来很是繁琐麻烦(由于要与现有数据对比后保存)。
var song = new Song { Id = 1 }; song.Tags = new List<Tag>(); song.Tags.Add(new Tag ...); song.Tags.Add(new Tag ...); song.Tags.Add(new Tag ...); repo.SaveManyToMany(song, "Tags"); //轻松保存 song 与 tag 表的关联
机制规则与联级保存的【多对多】同样,以下:
咱们对中间表的保存是完整对比操做,对外部实体的操做只做新增(注意不会更新)
fsql.CodeFirst.SyncStructure(typeof(Log), "Log_1"); //迁移到 Log_1 表 fsql.CodeFirst.SyncStructure(typeof(Log), "Log_2"); //迁移到 Log_2 表
在此功能上,咱们对分表功能作了点升级,如下动做都会作迁移动做:
fsql.Select<Log>().AsTable((_, oldname) => $"{oldname}_1"); fsql.GetRepository<Log>(null, oldname => $"{oldname}_1");
FreeSql 提供了多种插入或更新方法,v0.11 以前主要使用 FreeSql.Repository/FreeSql.DbContext 库提供的方法实现。
FreeSql.Repository 之 InsertOrUpdate
此方法与 FreeSql.DbContext AddOrUpdate 方法功能同样。
var repo = fsql.GetRepository<T>(); repo.InsertOrUpdate(实体);
若是内部的状态管理存在数据,则更新。
若是内部的状态管理不存在数据,同查询数据库,是否存在。
存在则更新,不存在则插入
缺点:不支持批量操做
FreeSql.Provider.MySql 和 FreeSql.Provider.MySqlConnector 在 v0.11.11 版本已支持 MySql 特有的功能,On Duplicate Key Update。
这个功能也能够实现插入或更新数据,而且支持批量操做。
class TestOnDuplicateKeyUpdateInfo { [Column(IsIdentity = true)] public int id { get; set; } public string title { get; set; } public DateTime time { get; set; } } var item = new TestOnDuplicateKeyUpdateInfo { id = 100, title = "title-100", time = DateTime.Parse("2000-01-01") }; fsql.Insert(item) .NoneParameter() .OnDuplicateKeyUpdate().ToSql(); //INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`, `time`) VALUES(100, 'title-100', '2000-01-01 00:00:00.000') //ON DUPLICATE KEY UPDATE //`title` = VALUES(`title`), //`time` = VALUES(`time`)
OnDuplicateKeyUpdate() 以后能够调用的方法:
方法名 | 描述 |
---|---|
IgnoreColumns | 忽略更新的列,机制和 IUpdate.IgnoreColumns 同样 |
UpdateColumns | 指定更新的列,机制和 IUpdate.UpdateColumns 同样 |
Set | 手工指定更新的列,与 IUpdate.Set 功能同样 |
SetRaw | 做为 Set 方法的补充,可传入 SQL 字符串 |
ToSql | 返回即将执行的 SQL 语句 |
ExecuteAffrows | 执行,返回影响的行数 |
IInsert 与 OnDuplicateKeyUpdate 都有 IgnoreColumns、UpdateColumns 方法。
当插入实体/集合实体的时候,忽略了 time 列,代码以下:
fsql.Insert(item) .IgnoreColumns(a => a.time) .NoneParameter() .OnDuplicateKeyUpdate().ToSql(); //INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(200, 'title-200') //ON DUPLICATE KEY UPDATE //`title` = VALUES(`title`), //`time` = '2000-01-01 00:00:00.000'
咱们发现,UPDATE time 部分变成了常量,而不是 VALUES(`time`),机制以下:
当 insert 部分中存在的列,在 update 中将以 VALUES(`字段`) 的形式设置;
当 insert 部分中不存在的列,在 update 中将为常量形式设置,当操做实体数组的时候,此常量为 case when ... end 执行(与 IUpdate 同样);
使用方法 MySql OnDuplicateKeyUpdate 大体相同。
默认 IDelete 不支持导航对象,多表关联等。ISelect.ToDelete 可将查询转为删除对象,以便支持导航对象或其余查询功能删除数据,以下:
fsql.Select<T1>().Where(a => a.Options.xxx == 1).ToDelete().ExecuteAffrows();
注意:此方法不是将数据查询到内存循环删除,上面的代码产生以下 SQL 执行:
DELETE FROM `T1` WHERE id in (select a.id from T1 a left join Options b on b.t1id = a.id where b.xxx = 1)
复杂删除使用该方案的好处:
还有 ISelect.ToUpdate 高级更新数据功能,使用方法相似
FreeSql 基础层实现了 Select/Update/Delete 可设置的全局过滤器功能。
public static AsyncLocal<Guid> TenantId { get; set; } = new AsyncLocal<Guid>(); fsql.GlobalFilter .Apply<TestAddEnum>("test1", a => a.Id == TenantId.Value) .Apply<AuthorTest>("test2", a => a.Id == 111) .Apply<AuthorTest>("test3", a => a.Name == "11");
Apply 泛型参数能够设置为任何类型,当使用 Select/Update/Delete 方法时会进行过滤器匹配尝试(try catch):
如何禁用?
fsql.Select<TestAddEnum>().ToList(); //全部生效 fsql.Select<TestAddEnum>().DisableGlobalFilter("test1").ToList(); //禁用 test1 fsql.Select<TestAddEnum>().DisableGlobalFilter().ToList(); //禁用全部
fsql.Update/Delete 方法效果同上。
注意:IFreeSql.GlobalFilter 与 仓储过滤器 不是一个功能,能够同时生效
感谢反馈 bug 的朋友!
仓库地址:https://github.com/2881099/FreeSql
请移步更新日志:https://github.com/2881099/FreeSql/wiki/%e6%9b%b4%e6%96%b0%e6%97%a5%e5%bf%97
原文出处:https://www.cnblogs.com/kellynic/p/11881941.html