- 本文已参与「新人创作礼」活动,一起开启掘金创作之路。
FreeSql是什么?
FreeSql 是一款功能强大的对象关系映射(O/RM)组件!为什么要使用FreeSql呢?官方给出了下面优势,通过我个人使用来看,还是非常的不错的,功能也非常强大,就是语法让我非常的不习惯,感觉像Linq又像再写Sql,只能说他的语法非常丰富且强大.....。
- 🛠 支持 CodeFirst 模式,即便使用 Access 数据库也支持数据迁移;
- 💻 支持 DbFirst 模式,支持从数据库导入实体类,或使用实体类生成工具生成实体类;
- ⛳ 支持 深入的类型映射,比如 PgSql 的数组类型等;
- ✒ 支持 丰富的表达式函数,以及灵活的自定义解析;
- 🏁 支持 导航属性一对多、多对多贪婪加载,以及延时加载;
- 📃 支持 读写分离、分表分库、过滤器、乐观锁、悲观锁;
- 🌳 支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite/Firebird/达梦/人大金仓/神舟通用/南大通用/翰高/ClickHouse/Access 等数据库;
如何在.NET Core中使用FreeSql?
本文代码都是单一项目结构,没有分层没有任何架构,使用的时候可以根据自己项目结构或者架构合理将ORM放入到适合的模块,有利于开发人员更好阅读以及理解项目。
主要依赖的包有FreeSql 以及 FreeSql.Provider.SqlServer
声明
新增FreeSqlDb类,用于声明FreeSql。包括了多个方法,下面代码只使用了两个,还有一些可以阅读官方文档按需使用
public class FreeSqlDb
{
public IFreeSql freeSql { get; private set; }
public FreeSqlDb()
{
freeSql = new FreeSql.FreeSqlBuilder()
//连接串 1.为数据库类型,2.为数据库连接串
.UseConnectionString(FreeSql.DataType.SqlServer, @"server=localhost;database=Book")
//自动同步实体结构到数据库,程序运行中检查实体表是否存在,然后创建或修改[生产环境慎用]
.UseAutoSyncStructure(true)
.Build();
}
}
//在项目初始化StartUp类或者Program类初始化FreeSql
//要定义成单例模式,而不是在每次使用的时候创建。
builder.Services.AddSingleton<FreeSqlDb>();
CodeFirst
FreeSql支持Codefirst,这当然也是ORM框架的标配。它还提供了许多特性,正如FreeSql文中所写:
优点是充分利用数据库特性辅助开发,缺点是切换数据库变得困难。如何使用Code First呢?FreeSql提供了两种实现方式,第一种就是在初始化的时候UseAutoSyncStructure置为True实现自动迁移,第二种是手动。下面为大家展示用法。
- 新增Model文件夹,用于存放项目所使用的所有实体类,在文件夹新增实体类Book,实体所标注的特性由FreeSql提供
[Table(Name = "tb_book")] //实体特性,当表名称与实体名称各自命名无法对应,可以使用Table特性
public class Book
{
//IsPrimary 如果没有指定主键 系统会自动将Id命名的字段设为主键 IsIdentity 设置自增
[Column(IsPrimary = true,IsIdentity = true)]
public int Id { get; set; }
[Column(DbType = "varchar(128) NOT NULL")] // 指定数据库类型
public string BookName { get; set; }
[Column(StringLength = -1)] // 当数据库存放字符串长度过长可以使用 等比于nvarchar(max)
public string Description { get; set; }
[Column(DbType = "decimal(10,2)")]
public decimal Price { get; set; }
// 服务器时间类似于在插入的时候getdate(),CanUpdate 表示更新的时候忽略这个字段
[Column(ServerTime = DateTimeKind.Utc, CanUpdate = false)]
public DateTime CreateTime { get; set; }
}
- 新增BookController,创建Add方法,我们一起来测试看看数据是否能新增成功,会不会为我们生成表呢!
// 注入我们之前初始化 FreeSqlDb 类
private readonly FreeSqlDb _freeSql;
public BookController(FreeSqlDb freeSql)
{
_freeSql = freeSql;
}
[HttpPost]
public async Task Add(Book book)
{
// 执行Insert方法,返回受影响行数
var count = await _freeSql.freeSql.Insert(book).ExecuteAffrowsAsync();
if (count <= 0)
throw new Exception("数据库新增失败,请仔细检查!");
}
通过上图可以看出,将我们模型中配置的特性已经得到了体现,为我们生成了表,数据也新增成功了!
注意:
FreeSql不会帮你生成数据库,需要你手动创建数据库,需要自动创建数据库.请参考此代码FreeSqlExtension.cs,关于另外一种手动生成,本文就不在演示,相信观看上面方法,实现起来也是非常容易的。
查询
FreeSql 在查询数据下足了功夫,链式查询语法、多表查询、表达式函数支持得非常到位。
[HttpGet]
public async Task Get(int page,int limit)
{
// 分页查询
var list = await _freeSql.freeSql.Select<Book>()
.Where(a => a.Id > 10) //查询条件
.OrderBy(a => a.CreateTime) //为了分页次序明确,建议先排序再Count
.Count(out var total) //总记录数量
.Page(page, limit)
.ToListAsync();
// 连表查询
var joinList = await _freeSql.freeSql.Select<Book, BookType>()
//配置了导航属性,则不需要手工调用LeftJoin
.LeftJoin((a, b) => a.TypeId == b.Id)
.ToListAsync((a, b) => new { a, b });
// 查询单条数据
Book book = await _freeSql.freeSql.Select<Book>().ToOneAsync();
// withsql
await _freeSql.freeSql.Select<Book>()
.WithSql("select * from Book where id > @val", new { val = 10 })
.Page(1, 10)
.ToList()
}
不得不说,查询方法真是非常的强大,本文就不一一展示,感兴趣的朋友赶紧上手试试吧查询文档
丰富的表达式
- 查找今天创建的数据
var list = await _freeSql.freeSql.Select<Book>()
.Where(a => a.CreateTime.Date == DateTime.Today)
.ToListAsync();
- In查询
var list = await _freeSql.freeSql.Select<Book>()
.Where(a => new[] { 1, 2, 3 }.Contains(a.Id))
.ToList();
这里就简单的列举了几个,确实是太多了!!!
事务
FreeSql支持多种事务,包括 UnitOfWork 事务、 DbContext 事务、同线程事务、外部事务等等,还支持分布式事务,我未作过多了解这里就不给大家说明了,感兴趣可以阅读相关源码、文档
_freeSql.freeSql.Transaction(() => {
//fsql.Ado.TransactionCurrentThread 获得当前事务对象
// 新增Book
var count = _freeSql.freeSql.Insert(book).ExecuteAffrows();
if (count < 1)
throw new Exception("新增失败");
//抛出异常,回滚事务,事务退出
var affrows = _freeSql.freeSql.Insert<Notice>(notice)
.ExecuteAffrows();
// 给通知中心存取记录
if (affrows < 1)
throw new Exception("新增失败");
//抛出异常,回滚事务,事务退出
});
上面代码展示的是同线程事务,每个线程只可开启一个事务连接,他的缺点就是不能使用异步方法。
总结
FreeSql 实现了强大功能的同时,性能没有受到影响,项目中使用反射或耗时的操作都经过了缓存处理。不得不说确实厉害,具体使用还是得看公司技术决策,或者场景来决定是否使用,虽然在性能方面不如Dapper但是在一些功能上面我觉得相比起Dapper还是更加好用的。本文阐述的内容如果有不正确的地方,还请各位朋友们指出,我会及时修改!