FreeSql 采用 ExpressionTree 优化读取速读,如果懂技术的你一定知道 .NETCore 技术下除了原生代码,最快就是 Emit 和 ExpressionTree。
项目在初期使用的反射+缓存,虽然 .NETCore 优化了反射性能,但经过与Dapper性能测试对比之后,发现仍然有一定差距,改成 ExpresstionTree 后才与 Dapper 性能相当。
FreeSql 支持的类型较多,实现 ExpressionTree 的复杂度较大,有兴趣的朋友可以翻阅源代码。
IFreeSql fsql = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10")
.Build();
[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 select => fsql.Select();
返回单条记录
Topic t1 = select.Where(a => a.Id == 1).ToOne();
FreeSql有一个约定,ToOne 永远返回 null 或 有数据的实体对象,ToList 永远返回非 null 的 List<实体类型>
返回 List
List t1 = select.Where(a => a.Id > 0).Skip(100).Limit(200).ToList();
返回 List + 导航属性的数据
List t2 = select.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid).ToList();
//此时会返回普通字段 + 导航对象 Type 的数据
指定字段返回
//返回一个字段
List t3 = select.Where(a => a.Id > 0).ToList(a => a.Id);
//返回匿名类
List<匿名类> t4 = select.Where(a => a.Id > 0).ToList(a => new { a.Id, a.Title });
//返回元组
List<(int, string)> t5 = select.Where(a => a.Id > 0).ToList<(int, string)>("id, title");
//返回指定映射字段
List<(int, string)> t6 = select.Where(a => a.Id > 0).ToList();
//返回SQL字段
List<匿名类> t7 = 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<匿名类> t8 = select.From((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 t9 = fsql.Ado.Query("select * from song");
List<(int, string ,string)> t10 = fsql.Ado.Query<(int, string, string)>("select * from song");
List t11 = fsql.Ado.Query("select * from song");
巧用AsTable
var t12 = fsql.Select()
.AsTable((a, b) => "(select * from tb_topic where clicks > 10)")
.Page(1, 10).ToList()
ToChunk
执行查询,分块返回数据,可减少内存开销。比如读取10万条数据,每次返回100条处理。
var testlist1 = fsql.Select().OrderBy(a => a.Id).ToList();
var testlist2 = new List();
fsql.Select().OrderBy(a => a.Id).ToChunk(100, list =>
{
testlist2.AddRange(list);
});
//这里示范,最终 testlist1 与 testlist2 返回的数据相同。
API
方法 | 返回值 | 参数 | 描述 |
---|---|---|---|
ToSql | string | 返回即将执行的SQL语句 | |
ToList | List | 执行SQL查询,返回 T1 实体所有字段的记录,若存在导航属性则一起查询返回,记录不存在时返回 Count 为 0 的列表 | |
ToList |
List |
Lambda | 执行SQL查询,返回指定字段或Dto映射的记录,记录不存在时返回 Count 为 0 的列表 |
ToList |
List |
string field | 执行SQL查询,返回 field 指定字段的记录,并以元组或基础类型(int,string,long)接收,记录不存在时返回 Count 为 0 的列表 |
ToOne | T1 | 执行SQL查询,返回 T1 实体所有字段的第一条记录,记录不存在时返回 null | |
ToChunk | <空> | int size, Action
|
执行SQL查询,分块返回数据,可减少内存开销。比如读取10万条数据,每次返回100条处理。 |
Any | bool | 执行SQL查询,是否有记录 | |
Sum | T | Lambda | 指定一个列求和 |
Min | T | Lambda | 指定一个列求最小值 |
Max | T | Lambda | 指定一个列求最大值 |
Avg | T | Lambda | 指定一个列求平均值 |
系列文章导航
(一)入门
(二)自动迁移实体
(三)实体特性
(四)实体特性 Fluent Api
(五)插入数据
(六)批量插入数据
(七)插入数据时忽略列
(八)插入数据时指定列
(九)删除数据
(十)更新数据
(十一)更新数据 Where
(十二)更新数据时指定列
(十三)更新数据时忽略列
(十四)批量更新数据
(十五)查询数据
(十六)分页查询
(十七)联表查询
(十八)导航属性
(十九)多表查询
(二十)多表查询 WhereCascade
(二十一)查询返回数据
(二十二)Dto 映射查询
(二十三)分组、聚合
(二十四)Linq To Sql 语法使用介绍
(二十五)延时加载
(二十六)贪婪加载 Include、IncludeMany、Dto、ToList
(二十七)将已写好的 SQL 语句,与实体类映射进行二次查询
(二十八)事务
(二十九)Lambda 表达式
(三十)读写分离
(三十一)分区分表
(三十二)Aop
(三十三)CodeFirst 类型映射
(三十四)CodeFirst 迁移说明
(三十五)CodeFirst 自定义特性