讓EFCore更瘋狂些的擴展類庫(二):查詢緩存、分部sql、表名替換的策略配置

来源:http://www.cnblogs.com/skig/archive/2017/01/19/EFCoreExtend-2.html
-Advertisement-
Play Games

前言 上一篇介紹了擴展類庫的功能簡介,通過json文件配置sql語句 和 sql語句的直接執行,這篇開始說明sql配置的策略模塊:策略管理器與各種策略的配置。 類庫源碼:github:https://github.com/skigs/EFCoreExtend 引用類庫:nuget:https://w ...


前言

上一篇介紹了擴展類庫的功能簡介,通過json文件配置sql語句 和 sql語句的直接執行,這篇開始說明sql配置的策略模塊:策略管理器與各種策略的配置。

  類庫源碼:github:https://github.com/skigs/EFCoreExtend

  引用類庫:nuget:https://www.nuget.org/packages/EFCoreExtend/

     PM> Install-Package EFCoreExtend

 

策略管理器功能簡介

用於管理策略 與 策略執行器和調用(目前分為三種策略執行器),目的為了讓配置的sql語句更加簡單、自動化等等。

1) 策略類型管理

  a) 管理各種策略類型,用於初始化配置文件中的策略配置轉換成對象

2) 策略對象配置

  a) 通過 sql配置的執行器 的形參傳遞策略對象

  b) 通過 配置文件(分為表和sql) 配置策略對象

  c) 配置到 全局策略 中(策略管理器中)

  d) 策略對象獲取的優先順序:通過執行器的形參傳遞的策略對象 > sql配置的策略對象 > 表配置的策略對象 > 全局策略中配置

3) 策略執行器(一般通過策略對象進行相應的處理)

  a) 初始化型的策略執行器:這種類型的會在第一次調用GetExecutor的時候執行,只會執行一次,除非sql配置有改動

    1.  配置策略對象的初始化、替換表名、合併分部sql等的策略執行器

  b) sql執行前的策略執行器:一般用於對SqlParameter進行解析到sql中

    1.  foreach策略執行器:對SqlParameter或者某些數據類型(list/dictionary/model)進行遍歷生成字串替換到sql中

  c) sql執行時的策略執行器:一般用於緩存和日誌記錄

    1.  sql與參數的日誌記錄策略執行器
    2.  查詢緩存與清理策略執行器

 

表名替換策略

通過特定的標簽代替表名在sql配置中呈現(該策略對象預設已經添加到全局策略中,因此並不一定要在配置文件中配置):

{
  "policies": { //表配置的策略對象(會包含到表下的所有sql配置中)
    //表名策略
    "tname": {
      //"tag": "##tname"  //預設值為 ##tname
    }
  },
  "sqls": {
    "GetList": {
      "sql": "select * from ##tableName where name=@name", // => select * from [Person] where name=@name
      "type": "query",
      "policies": { //sql配置的策略對象
        //表名策略
        "tname": {
          "tag": "##tableName", //預設值為 ##tname
          "prefix": "[", //首碼
          "suffix": "]" //尾碼
        }
      }
    }
  }
}

配置初始化:

 1         public static void Init()
 2         {
 3             //載入配置
 4             EFHelper.Services.SqlConfigMgr.Config.LoadDirectory(Directory.GetCurrentDirectory() + "/Datas");
 5 
 6             //設置到全局策略中(一般用於設置 初始化型的策略對象),將策略對象設置到全局之後,會包含到所有配置中的
 7             EFHelper.Services.SqlConfigMgr.PolicyMgr.SetGlobalPolicy(
 8                 //TableNamePolicy對象預設已經添加到全局策略中
 9                 new TableNamePolicy    //表名策略在配置文件中呈現的key:tname(可以通過SqlConfigConst.TableNamePolicyName獲取)
10                 {
11                     Tag = "##tname",
12                 });
13         }

配置執行器調用:

 1         public IReadOnlyList<Person> GetList()
 2         {
 3             tinfo = db.GetConfigTable<Person>();
 4             return tinfo.GetExecutor().QueryUseModel<Person>(new
 5             {
 6                 name = "tom"
 7             }, null, null,
 8             //通過參數傳遞策略對象(一般用於設置 sql執行前 或 執行時的策略對象,
 9             //      而初始化型的一般在配置文件或全局策略中設置)
10             new[] { new SqlL2QueryCachePolicy() });
11         }

說明:

策略對象獲取的優先順序(如果策略對象設置到多個地方了): 執行器形參傳遞的策略對象 >  sql配置的策略對象 >  表配置的策略對象 >  全局策略中配置

 

分部sql策略

分部sql目的為了將sql分部在不同的配置中,以便sql的可重用:

Person.json配置:

{
  "sqls": {
    "GetListSection": {
      "sql": "select * from ##tname where #{WhereSec}",    
        //最終生成的sql:select * from Person where name=@name or addrid in (select id from Address where id=@addrid)
      "type": "query",
      "policies": {
        //分部sql策略,以便將sql分部在不同的配置中(註意:分部策略是對sql的分部,可以在分部sql下再進行分部sql(子分部),但是不會繼承分部sql中的policies(策略對象)等的配置)
        "section": {
          //"tagPrefix": "#{", //策略首碼標記符,預設為 #{
          //"tagSuffix": "}", //策略尾碼標記符,預設為 }
          "sqlNames": [ "WhereSec" ] //指定sql的名稱(同表下的SqlName)
          //"tableSqlNames": { //指定其他表的sql名稱(key為TableName,value為SqlName)
          //}
        }
      }
    },
    "WhereSec": {
      "sql": " #{WhereSec1} or addrid in (#{Address.ListSec}) ",
      "type": "nonexecute",    //不用於執行的sql類型
      "policies": {
        "section": {
          "sqlNames": [ "WhereSec1" ],
          "tableSqlNames": { //指定其他表的sql名稱(key為TableName,value為SqlName)
            "Address": "ListSec"
          }
        }
      }
    },
    "WhereSec1": {
      "sql": "name=@name",
      "type": "nonexecute"
    }
  }
}

Address.json

{
  "sqls": {
    "ListSec": {
      "sql": "select id from ##tname where #{WhereSec}",
      "type": "nonexecute",
      "policies": {
        "section": {
          "sqlNames": [ "WhereSec" ] //指定sql的名稱(同表下的SqlName)
        }
      }
    },
    "WhereSec": {
      "sql": "id=@addrid",
      "type": "nonexecute"
    }
  }
}
View Code

配置執行器調用:

1         public IReadOnlyList<Person> GetListSection()
2         {
3             tinfo = db.GetConfigTable<Person>();
4             return tinfo.GetExecutor().QueryUseModel<Person>(new
5             {
6                 name = name,
7                 addrid = 123,
8             });
9         }
View Code

 

查詢緩存與緩存清理策略

查詢緩存分為 一級緩存 和 二級緩存。

一級查詢緩存策略

一級緩存僅作用於SqlConfigExecutor對象中,而且不能設置緩存過期時間。

配置:

{
  "sqls": {
    "GetListL1Cache": {
      "sql": "select * from ##tname where name=@name",
      "type": "query",
      "policies": {
        "l1cache": {} //一級查詢緩存,僅作用於SqlConfigExecutor對象
      }
    }
  }
}
View Code

配置執行器調用:

        public void GetListL1Cache()
        {
            var tinfo = db.GetConfigTable<Person>();
            var exc = tinfo.GetExecutor();
            var q1 = exc.QueryUseModel<Person>(new { name = _name });
            var q2 = exc.QueryUseModel<Person>(new { name = _name });
            //一級緩存作用於SqlConfigExecutor,那麼同一個SqlConfigExecutor對象下,
            //  相同的sql和SqlParameter獲取的數據是一樣的
            Assert.True(q1 == q2);
            var q3 = exc.QueryUseModel<Person>(new { name = _name + "1" });
            //參數變了
            Assert.True(q1 != q3);
        }
View Code

二級查詢緩存策略

二級查詢緩存,作用於整個程式運行期間,也可配置到Redis中,如果同時配置了二級緩存和一級緩存預設是使用二級緩存(策略執行器的優先順序有關)。

配置:

{
  "name": "Person",
  "policies": {
    //二級查詢緩存,作用於整個程式運行期間 / 或者跨進程分散式(Redis),如果同時配置了二級緩存和一級緩存預設時使用二級緩存(策略執行器的優先順序有關)
    "l2cache": {
      //"type":"",  //緩存的類型(Query預設為:query, Scalar預設為:scalar)
      "expiry": { //註意如果沒有設置expiry的date/span,那麼緩存不會過期的
        //"date": "2018-01-01", //指定緩存的過期日期
        //"span": "00:00:03" //指定緩存的過期間隔(換算日期為:當前時間 + 時間間隔)
        //"isUpdateEach": true //是否每次獲取緩存之後更新過期時間(這個屬性 + span屬性來進行模擬session訪問更新過期時間)
      }
    }
  },
  "sqls": {
    "CountL2Cache": {
      "sql": "select count(*) from ##tname",
      "type": "scalar",
      "policies": {
        "l2cache": {
          "expiry": {
            "span": "00:00:03", //指定緩存的過期間隔,這裡設置為3秒
            "isUpdateEach": true //每次獲取緩存之後更新過期時間
          }
        }
      }
    }
  }
}

配置執行器調用:

        public int CountL2Cache(TimeSpan? span = null)
        {
            var tinfo = db.GetConfigTable<Person>();
            if (span.HasValue)
            {
                return (int)tinfo.GetExecutor().ScalarUseModel(null, null,
                    //通過形參傳遞緩存策略對象:更改為不自動更新時間的
                    new SqlL2QueryCachePolicy
                    {
                        Expiry = new QueryCacheExpiryPolicy(span.Value, false)
                    });
            }
            else
            {
                return (int)tinfo.GetExecutor().Scalar();
            }
        }
View Code

更多的配置說明:

{
  "name": "Person",
  "sqls": {
    "GetListL2Cache": {
      "sql": "select * from ##tname",
      "type": "query",
      "policies": {
        "l2cache": { //二級查詢緩存,不設置緩存過期時間(緩存不過期)
        }
      }
    },
    "GetListL2Cache1": {
      "sql": "select * from ##tname",
      "type": "query",
      "policies": {
        "l2cache": {
          "type": "query1" //指定CacheType,預設為query
        }
      }
    },
    "GetListL2Cache2": {
      "sql": "select * from ##tname where 2=2",
      "type": "query",
      "policies": {
        "l2cache": {
          "expiry": {
            "date": "2018-01-01" //指定緩存的過期日期
          }
        }
      }
    },
    "GetListL2Cache3": {
      "sql": "select * from ##tname where 3=3",
      "type": "query",
      "policies": {
        "l2cache": {
          "expiry": {
            "span": "00:00:03" //指定緩存的過期間隔(換算日期為:當前時間 + 時間間隔),為了方便測試因此這裡指定了3秒
          }
        }
      }
    },
    "CountL2Cache": {
      "sql": "select count(*) from ##tname",
      "type": "scalar",
      "policies": {
        "l2cache": {
          "expiry": {
            "span": "00:00:03", //指定緩存的過期間隔(換算日期為:當前時間 + 時間間隔),為了方便測試因此這裡指定了3秒
            "isUpdateEach": true //是否每次獲取緩存之後更新過期時間(這個屬性 + span屬性來進行模擬session訪問更新過期時間)
          }
        }
      }
    }
  }
}
View Code

二級緩存清理策略

配置:

{
  "policies": {
    //二級查詢緩存清理策略
    "clear": {
      "isAsync": true,//是否非同步進行清理
      "isSelfAll": true, //是否清理 所在表下 的所有緩存
      "tables": [ "Address" ], //需要進行緩存清理的表的名稱(一般用於清理 其他表下 的所有查詢緩存)
      "cacheTypes": [ "query", "scalar1" ], //需要進行緩存清理的類型(用於清理 所在表下 的CacheType查詢緩存)
      "tableCacheTypes": { //需要進行緩存清理的類型(key為TableName,value為CacheType,一般用於清理 其他表下 的CacheType)
        "Address": "query"
      }
    }
  },
  "sqls": {
    "CountL2Cache": {
      "sql": "select count(*) from ##tname",
      "type": "scalar",
      "policies": {
        "l2cache": {
          "type": "scalar1", //緩存的類型(Query預設為:query, Scalar預設為:scalar)
          "expiry": {
            "span": "00:00:03"
          }
        }
      }
    },
    "AddPersonL2Cache": {
      "sql": "insert into ##tname(name, birthday, addrid) values('tom_t2cache', '2018-1-1', 123) ",
      "type": "nonquery",
      "policies": {
        "clear": {
          "isSelfAll": true //是否清理 所在表下 的所有緩存
        }
      }
    }
  }
}
View Code

配置執行器調用:

 1     public class PersonBLL
 2     {
 3         DBConfigTable tinfo;
 4         public PersonBLL(DbContext db)
 5         {
 6             tinfo = db.GetConfigTable<Person>();
 7         }
 8 
 9         public int CountL2Cache()
10         {
11             return (int)tinfo.GetExecutor().Scalar();
12         }
13 
14         public int AddPersonL2Cache()
15         {
16             return tinfo.GetExecutor().NonQuery();
17         }
18     }
View Code

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這幾天老感覺不對, 總覺得少點什麼, 今天才發現, 前面 3 裡面, 在獲取Action參數信息的時候, 少解析了. 裡面還有一個比較重要的東西. 今天看也是一樣的. 在 InvokeAction() 方法裡面, 有一句代碼: 這個是用來獲取參數的. 那麼參數是不是隨便獲取呢? 在Mvc 裡面, 頁 ...
  • 16年我們公司一共開發了好幾個企業網站。最初項目經理讓我用模板引擎,我參照著網上找的模板引擎的代碼及功能,自己寫了一個。當開發了幾個企業網站之後,發現開發效率太低了,同事們用模板引擎開發的過程中,寫模板改模板要花費不少時間,有時候特殊的需求,需要加個資料庫表,或者資料庫已有的欄目或內容表加個欄位什麼 ...
  • 因為一些配置屬性比較多,存在多組屬性,因此結合xml解析、緩存技術,實現配置文化的自動解析、存入緩存、緩存依賴實時更新配置內容。 配置文件反序列化存入緩存的核心方法: public Class.Settings GetSettings() { if (HttpRuntime.Cache["setti ...
  • 網上對TempData的總結為: 保存在session中,Controller每次執行請求時,會從session中一次獲取所有tempdata數據,保存在單獨的內部數據字典中,而後從session中清空tempdata。然後通過key從字典中獲取指定的Tempdata,每訪問一次後對應的Key就會從 ...
  • 比AutoMapper輕量快速簡潔的實體映射庫YeaJur.Mapper ...
  • 在上一篇文章中,我們已經瞭解到瞭如何在SuperSocket處理客戶端請求。 同時我們可能會發現一個問題,如果我們的伺服器端包含有很多複雜的業務邏輯,這樣的switch/case代碼將會很長而且非常難看,並且沒有遵循面向對象設計的原則(OOD)。 在這種情況下,SuperSocket提供了一些讓我們 ...
  • 更新內容:宿主的唯一編號和名稱可以輸入符號"."日誌文本框增加滾動條,並且總是顯示文本末端增加啟動方式選擇:1.手動啟動 2.跟隨系統啟動 最新下載地址: http://pan.baidu.com/s/1dEAs3Vr 密碼:8d9t 使用說明: http://www.cnblogs.com/Myt ...
  • 採用單位矩陣行列式變換求逆矩陣,源碼展示: public static double[,] Inverse(double [,] Array) { int m = 0; int n = 0; m = Array.GetLength(0); n = Array.GetLength(1);... ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...