FreeSql 项目从2018年11月28日开发至今,版本已发布至 v0.3.12,版本规则:年数-月-日-当日版本号。目前主要包括 FreeSql、FreeSql.Repository 两个项目的维护和开发。这篇文章介绍有哪些贴心功能。html
错误:传入的请求具备过多的参数。该服务器支持最多 2100 个参数。请减小参数的数目,而后从新发送该请求。git
不知道其余 orm 批量添加实体到 sqlserver 有没有这个错误,FreeSql 不存在。github
每款 orm 都会有本身一套实体类配置方法,当项目的实体被多个 orm 同时使用时将成为问题,由于不可能作多套配置,FreeSql 提供了如下几种的方法,免入侵式配置;sql
一、若是你从数据库生成的实体,FreeSql 提供 IsConfigEntityFromDbFirst 参数,可从数据库导入主键、自键等配置信息;数据库
var orm = 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") .UseAutoSyncStructure(true) //只须要在这里控制,默认为关闭状态 .UseConfigEntityFromDbFirst(true) .Build();
二、若是你已经使用 EF 建好了实体模式,FreeSql 提供了从 EF 元数据导入;数组
public static void ConfigEntity(this ICodeFirst codeFirst, IModel efmodel) { foreach (var type in efmodel.GetEntityTypes()) { codeFirst.ConfigEntity(type.ClrType, a => { //表名 var relationalTableName = type.FindAnnotation("Relational:TableName"); if (relationalTableName != null) { a.Name(relationalTableName.Value?.ToString() ?? type.ClrType.Name); } foreach (var prop in type.GetProperties()) { var freeProp = a.Property(prop.Name); //列名 var relationalColumnName = prop.FindAnnotation("Relational:ColumnName"); if (relationalColumnName != null) { freeProp.Name(relationalColumnName.Value?.ToString() ?? prop.Name); } //主键 freeProp.IsPrimary(prop.IsPrimaryKey()); //自增 freeProp.IsIdentity( prop.ValueGenerated == ValueGenerated.Never || prop.ValueGenerated == ValueGenerated.OnAdd || prop.GetAnnotations().Where(z => z.Name == "SqlServer:ValueGenerationStrategy" && z.Value.ToString().Contains("IdentityColumn") //sqlserver 自增 || z.Value.ToString().Contains("IdentityColumn") //其余数据库实现未经测试 ).Any() ); //可空 freeProp.IsNullable(prop.AfterSaveBehavior != PropertySaveBehavior.Throw); //类型 var relationalColumnType = prop.FindAnnotation("Relational:ColumnType"); if (relationalColumnType != null) { var dbType = relationalColumnType.ToString(); if (!string.IsNullOrEmpty(dbType)) { var maxLength = prop.FindAnnotation("MaxLength"); if (maxLength != null) dbType += $"({maxLength})"; freeProp.DbType(dbType); } } } }); } }
三、若是你使用了其余 orm,FreeSql 提供 ConfigEntity,使用相似 2 的作法来完成配置导入;安全
FreeSql 提供了同线程事务、对外开放事务。服务器
假设用户购买了价值100元的商品:异步
第一步:扣余额;ide
第二步:扣库存;
第一步成功了,到了第二步发现库存不足时,事务能够回滚,扣余额的数据将不生效。
//假设已经有了其余wiki页的IFreeSql声明 orm.Transaction(() => { var affrows = orm.Update<User>().Set(a => a.Wealth - 100) .Where(a => a.Wealth >= 100) //判断别让用户余额扣成负数 .ExecuteAffrows(); if (affrows < 1) { throw new Exception("用户余额不足"); //抛出异常,事务退出 } affrows = orm.Update<Goods>().Set(a => a.Stock - 1) .Where(a => a.Stock > 0) //判断别让用库存扣成负数 .ExecuteAffrows(); if (affrows < 1) { throw new Exception("商品库存不足"); //抛出异常,回滚事务,事务退出 //用户余额的扣除将不生效 } //程序执行在此处,说明都扣成功了,事务完成并提交 });
注意与说明:
一、数据库事务在线程挂载,每一个线程只可开启一个事务链接,重复开启会获取线程已开启的事务;
二、在事务代码过程当中,不可以使用异步方法,包括FreeSql提供的数据库异步方法,不然线程将会切换事务不生效;
三、orm.Transaction 有防止死锁机制,60秒事务未结束的,将会被其余线程强行提交(不是回滚),可能形成不完整的事务,但仔细一想60秒还没完成的事务是什么缘由呢?若是嫌60秒太少了能够在重载方法的参数中设置;
除了上面提供的同线程事务外,FreeSql 还提供了指定事务对象的方法,将事务对象暴露给外部;
orm.Update<xxx>().WithTransaction(指定事务) .Set(a => a.Clicks + 1).ExecuteAffrows();
ISelect、IInsert、IUpdate、IDelete,都支持 WithTransaction 方法。
dotnet add package FreeSql.Repository
一、IFreeSql 的扩展方法;
var curd1 = orm.GetRepository<Song, int>(); var curd2 = orm.GetGuidRepository<Song>();
二、继承现实;
public class SongRepository : BaseRepository<Song, int> { public SongRepository(IFreeSql orm) : base(orm) {} //在这里增长 CURD 之外的方法 }
三、Autofac 注入;
public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddSingleton<IFreeSql>(orm); services.AddMvc(); var builder = new ContainerBuilder(); //示范全局过滤的仓储类注入,若是实体中不存在 Title 属性,则条件不生效 builder.RegisterFreeRepositoryAddFilter<Song>(() => a => a.Title == DateTime.Now.ToString() + System.Threading.Thread.CurrentThread.ManagedThreadId); builder.Populate(services); var container = builder.Build(); return new AutofacServiceProvider(container); } //在控制器使用 public SongsController(GuidRepository<Song> repos1, GuidRepository<xxxx> repos2) { }
Autofac 注入方式实现了全局【过滤与验证】的设定,方便租户功能的设计;
In查询
var t1 = orm.Select<xxx>().Where(a => new[] { 1, 2, 3 }.Contains(a.testFieldInt)).ToSql(); //SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a.`Title`, a.`CreateTime` //FROM `tb_topic` a //WHERE (a.`Id` in (1,2,3))
查找今天建立的数据
var t2 = orm.Select<xxx>().Where(a => a.CreateTime.Date == DateTime.Now.Date).ToSql();
不提供 SqlFunc 之类的伪函数,所支持的类型基本均可以使用对应的表达式函数,例如 日期、字符串、IN查询、数组(PostgreSQL的数组)、字典(PostgreSQL HStore)等等。
一、避免死锁的事务,超时自动提交;
二、未设置条件的删除、更新不生效;
三、仓储提供 filter 验证数据,确保数据的安全性;
......
github: https://github.com/2881099/FreeSql
wiki: https://github.com/2881099/FreeSql/wiki/
原文出处:https://www.cnblogs.com/kellynic/p/10512734.html