FreeSql 項目從2018年11月28日開發至今,版本已發佈至 v0.3.12,版本規則:年數-月-日-當日版本號。目前主要包括 FreeSql、FreeSql.Repository 兩個項目的維護和開發。這篇文章介紹有哪些貼心功能。git
錯誤:傳入的請求具備過多的參數。該服務器支持最多 2100 個參數。請減小參數的數目,而後從新發送該請求。github
不知道其餘 orm 批量添加實體到 sqlserver 有沒有這個錯誤,FreeSql 不存在。sql
每款 orm 都會有本身一套實體類配置方法,當項目的實體被多個 orm 同時使用時將成爲問題,由於不可能作多套配置,FreeSql 提供瞭如下幾種的方法,免入侵式配置;數據庫
一、若是你從數據庫生成的實體,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 驗證數據,確保數據的安全性;
......