讓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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...