Dapper.Common
Dapper.Common是基於Dapper的LINQ實現,支持.net core,遵循Linq語法規則、鏈式調用、配置簡單、上手快,支持Mysql,Sqlserver(目前只實現了這兩個數據庫,實現其他數據庫也很輕松),支持單表,多表,自定義函數等功能。源碼及其簡單,直白,解析Lambda只有300行左右代碼。嚴格區分C#函數和數據庫函數,你可以在表達式中調用C#函數(不推薦,推薦將計算結果保存到變量,在寫入lambda表達式),性能損失在表達式編譯:常量>變量>函數。損失多少可以通過ExpressionUtil.BuildExpression()來測試,幾萬次耗時百毫秒及別。
開源地址:https://github.com/1448376744/Dapper.Common
Nuget:Install-Package Dapper.Common -Version 1.5.0
0.Test
1.Mapper
public class User { /// <summary>
/// 如果表名與字段名一致,可以不用Column進行注解,主鍵采用類型的第一個屬性【不推薦】 /// name:用於映射字段名和數據庫字段不一致【完全可以用T4一鍵生成我GitHub有現成的】 /// key: /// 目前實現了Primary的定義,設置為Primary的字段update實體時,默認采用該字段為更新條件 /// isIdentity: /// 設置未true時在Insert時不會向該字段設置任何值 /// isColumn: /// 標識該字段是否在數據庫存在,用於擴展User而不在sql中生成該字段 /// </summary> [Column(name: "id", key: ColumnKey.Primary, isIdentity: true, isColumn: true)] public int? Id { get; set; } [Column(name:"nick_name")] public string NickName { get; set; } [Column(name: "create_time")] public DateTime? CreateTime { get; set; } }
2.Config
//在App啟動時執行一次即可 SessionFactory.AddDataSource(new DataSource() { Name = "mysql", Source = () => new SqlConnection("connectionString"), SourceType = DataSourceType.SQLSERVER, UseProxy = true//使用Session的靜態代理實現,記錄日志,執行耗時,線上環境建議關閉代理 });
//獲取數據庫上下文 using (var session = SessionFactory.GetSession("msql")) { //linq to sql }
3.Insert
var entity = new User() { CreateTime=DateTime.Now, NickName="dapper", }; //絕大部分接口可以設置condition已決定是否執行,支持批量更新 session.From<User>().Insert(entity,condition:1>2); //查看日志,如果出現異常,應該在catch里,查看session.Loggers var loggers = session.Loggers;
2.Update
var entity = new User()
{
Id=2,
NickName="李四"
};
//更新所有字段(where id=2),支持批量,顯然除NickName之外將被更新成null session.From<User>().Update(entity); //更新部分字段 session.From<User>() .Set(a => a.NickName, "李四", condition: true)//condition為true時更新該字段 .Set(a => a.Balance, a => a.Balance + 100)//余額在原來基礎增加100 .Where(a => a.Id.In(1,2,3))//將id為1,2,3的記錄進行更新 .Update();
3.Delete
//刪除id>5||nick_name like '%da%' session.From<User>() .Where(a=>a.Id>5||a.NickName.Like("da")) .Delete();
4.Single
//查詢全部字段 var user1 = session.From<User>() .Where(a=>a.Id==2) .Single(); //查詢部分字段 var user2 = session.From<User>() .Where(a => a.Id == 2) .Single(s=>new { s.Id, s.NickName });
5.Select
//查詢:where id in(1,2,3) var list = session.From<User>() .Where(a => a.Id.In("1,2,3".Split(','))) .Select();
6.Where
//構建動態查詢,condition: true執行,通過condition選擇分支,多個where之間用 and 連接 var list = session.From<User>() .Where(a => a.Id.In(1, 2, 3), condition: true) .Where(a => a.NickName.Like("da"), condition: false) .Where(a => a.Id > 2 || (a.NickName.Like("da") && a.Balance > 50)) .Where("select * from user_bill where user_bill.user_id=user.id")//同樣可以當作字符串拼接工具 .Select();
7.Function
/// <summary> /// 自定義函數 /// </summary> public static class MySqlFun { //這里使用泛型並不是必須的,只用函數名在數據庫存在即可,泛型為了指定返回數據類型 [Function]//Dapper.Common嚴格區分C#函數和數據庫函數,一定要用該特性標識數據庫函數 public static T COUNT<T>(T column) { return default(T); } [Function] public static T MAX<T>(T column) { return default(T); } [Function] public static T DISTINCT<T>(T column) { return default(T); }
[Function]
public static T DATE<T>(T column)
{
return default(T);
}
}
8.GroupBy
var list = session.From<Order>() .GroupBy(a => a.UserId)//多個條件可以new一個匿名對象,也可以並聯多個group .Having(a => MySqlFun.COUNT(MySqlFun.DISTINCT(a.UserId)) > 10)//count(distinct(user_id))>10 .Select(s => new { s.UserId, OrderCount = MySqlFun.COUNT(1L),//這里應該返回long int, MaxFee = MySqlFun.MAX(s.TotalFee) });
9.Join
var list = session.From<Order, User>() .Join((a, b) => a.UserId == b.Id, JoinType.Inner) .GroupBy((a, b) => a.UserId) .Having((a, b) => MySqlFun.COUNT(MySqlFun.DISTINCT(a.UserId)) > 10)//count(distinct(user_id))>10 .Select((a, b) => new { a.UserId, b.NickName, OrderCount = MySqlFun.COUNT(1L),//這里應該返回long int, MaxFee = MySqlFun.MAX(a.TotalFee) });
10.SubQuery
var list = session.From<Order>() .GroupBy(a => a.UserId) .Having(a => MySqlFun.COUNT(MySqlFun.DISTINCT(a.UserId)) > 10) .Select(a => new { a.UserId, UserName=Convert.ToString("select nick_name from user where user.id=order.user_id"),//如果這個子查詢返回的是int:Convert.ToInt32(sql) OrderCount = MySqlFun.COUNT(1L),//這里應該返回long int【這就是為什么定義成泛型函數】, MaxFee = MySqlFun.MAX(a.TotalFee) });
11.Page
//分頁應該寫在Where,Having,Group之后(如果有)
var list = session.From<User>() .Where(a=>a.NickName != null) .Page(1,10,out long total) .Select();
12.Take
var list = session.From<User>() .Take(5) .Select();
13.Skip
//從數據庫索引為1的位置(跳過1之前的記錄),獲取10
var list = session.From<User>() .Skip(1,10) .Select();
14.Sum
var list= session.From<User>() .Sum(s=>s.Balance*s.Id);
15.Exists
//內部采用exist子查詢判斷滿足where條件的記錄是否存在
var flag = seesion.From<User>() .Where(a=>a.Id > 10) .Exists();
16.OrderBy
var list1 = session.From<User>() .Order(a=>a.Id) .Select(); var list2 = session.From<User>() .GroupBy(a => MysqlFun.DATE(a.CreateTime)) .OrderByDescending(a => MysqlFun.DATE(a.CreateTime)) .Select(s=>new { Date=MysqlFun.DATE(s.CreateTime), Count = MysqlFun.Count(1L) });
17.Filter
var user =new User () {
Id = 12 Balance = 50, NickName = "張三", CreateTime = Datetime.Now }; //Filter會在Insert,Update,Select,過濾掉不想要的字段
//這將不會更新余額及創建時間 var row = session.From<User>() .Filter(f=>new { f.CreateTime, f.Balance, }) .Update(user);
18.Transaction
//獲取數據庫上下文 ISession session = null; try {
session=SessionFactory.GetSession(); //開啟事務 session.Open(true); //sql //提交事務 session.Commit(); } catch (Exception) { session?.Rollback(); throw; } finally { session?.Close(); }
19.Custom Page
//該策略可適用於百萬級別,單表條件查詢 //思想:先只查滿足條件的id,並分頁,然后where in (idArray)查詳情
//還有一種超高性能的分頁思想:每一頁更具上一頁最大id開始向下分頁查詢,同樣可以集成到這一個方法里(加個分頁類型參數)
public static Dapper.Extension.IQueryable<T> SPage<T>(this Dapper.Extension.IQueryable<T> queryable, int index, int count, out long total) where T : class, new() { total = 0; if (index <= 90000) { //采用limit queryable.Page(index, count, out total); } //對mysql進行擴展 else if (queryable is MysqlQuery<T> mysqlQuery) { total = queryable.Count(); var table = EntityUtil.GetTable<T>(); var idName = table.Columns.Find(f => f.ColumnKey == ColumnKey.Primary).ColumnName; //先只查詢主鍵字段並分頁 var where = mysqlQuery._whereBuffer.Length > 0 ? "where " + mysqlQuery._whereBuffer : ""; var orderby = mysqlQuery._orderBuffer.Length > 0 ? "order by" + mysqlQuery._orderBuffer : ""; var sql = string.Format("select {0} from {1} {2} {3} limit {4},{5}", idName, table.TableName, where, orderby, (index - 1) * count, count); var idArray = mysqlQuery._session.Query<long>(sql, mysqlQuery._param); //重置 mysqlQuery._whereBuffer.Clear(); //新建條件 if (idArray.Count() > 0) { queryable.Where(string.Format("{0} in @idArray", idName), p => p.Add("@idArray", idArray)); } } return queryable; } var row = Session.From<Member>() .SPage(2,2,out long total) .Select();