[NewLife.XCode]實體類詳解

 NewLife.XCode是一個有10多年曆史的開源數據中間件,由新生命團隊(2002~2019)開發完成並維護至今,以下簡稱XCode。

整個系列教程會大量結合示例代碼和運行日誌來進行深入分析,蘊含多年開發經驗於其中。

開源地址:https://github.com/NewLifeX/X (求star, 620+)

 

生成實體類

上一章《數據模型》講到模型文件Model.xml和腳本Build.tt,(nuget安裝NewLife.XCode後即可擁有)。

把Build.tt和Model.xml(可改名)放在同一個目錄,在Build.tt上右鍵“運行自定義工具”,“顯示所有文件”,即可看到生成的實體類文件。

**如果運行Build.tt出錯,可能是因爲找不到XCode.dll文件,可以先編譯一次項目,讓XCode.dll生成到項目輸出目錄即可

我們來試試以下模型(拷貝到Model.xml裏面):

<?xml version="1.0" encoding="utf-8"?>
<Tables Version="9.9.6940.24706" NameSpace="NewLife.School.Entity" ConnName="School" BaseClass="Entity" Output="">
  <Table Name="Class" TableName="xxx_class" Description="班級" DbType="SqlServer">
    <Columns>
      <Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="編號" />
      <Column Name="Name" ColumnName="xxx_Nameyyy" DataType="String" Master="True" Description="名稱" />
      <Column Name="CreateUser" DataType="String" Description="創建者" />
      <Column Name="CreateUserID" DataType="Int32" Description="創建者" />
      <Column Name="CreateTime" DataType="DateTime" Description="創建時間" />
      <Column Name="CreateIP" DataType="String" Description="創建地址" />
      <Column Name="UpdateUser" DataType="String" Description="更新者" />
      <Column Name="UpdateUserID" DataType="Int32" Description="更新者" />
      <Column Name="UpdateTime" DataType="DateTime" Description="更新時間" />
      <Column Name="UpdateIP" DataType="String" Description="更新地址" />
      <Column Name="Remark" DataType="String" Length="200" Description="備註" />
    </Columns>
  </Table>
  <Table Name="Student" Description="學生" DbType="SqlServer">
    <Columns>
      <Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="編號" />
      <Column Name="ClassID" DataType="Int32" Description="班級" />
      <Column Name="Name" DataType="String" Master="True" Description="名稱" />
      <Column Name="Sex" DataType="Int32" Description="性別" Type="XCode.Membership.SexKinds" />
      <Column Name="Age" DataType="Int32" Description="年齡" />
      <Column Name="Mobile" DataType="String" Description="手機" />
      <Column Name="Address" DataType="String" Description="地址" />
      <Column Name="CreateUserID" DataType="Int32" Description="創建者" />
      <Column Name="CreateTime" DataType="DateTime" Description="創建時間" />
      <Column Name="CreateIP" DataType="String" Description="創建地址" />
      <Column Name="UpdateUserID" DataType="Int32" Description="更新者" />
      <Column Name="UpdateTime" DataType="DateTime" Description="更新時間" />
      <Column Name="UpdateIP" DataType="String" Description="更新地址" />
      <Column Name="Remark" DataType="String" Length="200" Description="備註" />
    </Columns>
    <Indexes>
      <Index Columns="ClassID" />
    </Indexes>
  </Table>
</Tables>

運行build.tt後

每個模型表,生成了四個實體類文件,選中它們幷包含到項目中。

其中Biz常稱之爲業務類,多次build.tt生成不覆蓋;

另一個稱之爲數據類,每次build.tt生成均覆蓋;

這裏採用了C#的分部類(partial)技術,一個類由兩個或多個類文件組成。

數據類包含表名(類名)字段名(屬性)等信息,修改模型文件後,每次生成都會覆蓋文件。

業務類包含其它非表結構信息,供開發者填寫代碼,所以只有首次生成,而再次生成時不會覆蓋。

數據類包括一個接口(如IStudent),以滿足精簡需要的場合。

數據類內部還有兩個內嵌類_和__,可用於快速訪問字段信息以及屬性名。

 

實體靜態構造函數

XCode是充血模型,因此實體類除了各個代表着表結構信息的屬性外,還會有大量用戶代碼在其中,並且繼承泛型實體基類(如Entity<User>)。

一個常見的實體類構造函數如下:

static User()
{
    // 累加字段
    var df = Meta.Factory.AdditionalFields;
    df.Add(__.Logins);

    // 過濾器 UserModule、TimeModule、IPModule
    Meta.Modules.Add<UserModule>();
    Meta.Modules.Add<TimeModule>();
    Meta.Modules.Add<IPModule>();

    // 單對象緩存
    var sc = Meta.SingleCache;
    sc.FindSlaveKeyMethod = k => Find(__.Name, k);
    sc.GetSlaveKeyMethod = e => e.Name;
}

這裏首先介紹一個最重要的實體類內嵌類Meta,它位於Entity<TEntity>.Meta,記錄着實體類的一切元數據,承載着實體類的一切高級功能!

 

Meta.Factory.AdditionalFields用於存放累加字段

一般更新語句 update user set Logins=123 where id=1,而把Logins字段設爲累加字段後,將得到 update user set Logins=Logins+33 where id=1 ,特別適用於併發更新同一行記錄的場合。

 

實體過濾器EntityModule,用於攔截實體類的添刪改操作,內置最常用的3個過濾器UserModule/TimeModule/IPModule

上一章末尾推薦的8個常用字段還記得嗎? CreateUser/CreateTime/CreateIP 等,所有CreateAbc將在Insert的時候攔截賦值,所有UpdateAbc將在Insert和Update的時候攔截賦值。

UserModule取當前登錄用戶,由ManageProvider驅動;

TimeModule取當前時間;

IPModule取當前訪問IP,由ManageProvider.UserHost提供;

 

緩存配置

單對象緩存是一個字典緩存,默認以主鍵爲key,實體對象爲value。

單對象緩存支持第二個字典,如上,配置Name爲第二字典的主鍵,實體對象爲value。

 

實體基類

當然,實體類靜態構造函數還可以用於其它用途,它將會在使用該實體類任意方法(包括成員方法和靜態方法)之前執行。

有時候把一個系統模塊放到一個獨立子目錄裏面,獨享一個“Abc.xml”模型文件,生成的實體類在目錄裏面,這個時候可以讓它們繼承一個相同的實體基類(如EntityBase)。

然後在實體基類EntityBase的靜態構造函數中寫入這個模塊所共有的代碼。

 

初始化數據

有些數據表需要默認初始化一些數據,如類別表、配置表等,便於開發測試。

這個時候可以重載InitData方法,它會在實體類第一次訪問數據庫之前執行。

這裏遇到Meta的第二次用法Meta.Count,該屬性表示當前實體類數據表的總行數。

當總行數在100萬以內時,數字精確等於 select count(*) from table,大於100萬時,將採用特有的快速方法。

Meta.Count帶緩存,擁有極好的性能,可用於粗略(數值較小時精確)估算該表總行數。

 

這裏通過Meta.Count來判斷該表是否爲空表,然後對空表插入一些默認數據。

 

數據驗證Valid

每個實體類在Insert/Update之前,都需要Valid驗證數據 ,參數isNew以區分Insert。

Valid常常可用於判斷主要字段的有效性,無效時強烈推薦拋出參數類異常,魔方NewLife.Cube表單將可以捕獲並定位。

除此之外,Valid用得更多的功能是在Insert/Update之前修改完善字段數據,例如上面對密碼進行MD5散列,以及格式化RoleIDs。

這裏出現新技術,IsDirty和Dirtys,這是XCode的髒數據,前者判斷Password字段是否有髒數據(Password被賦予跟原來不想等的值),後者清空Password髒數據。

髒數據是生成Update語句的核心,不髒的字段不會出現在update set 之中,實現部分字段更新,後續有專門章節講解。

 

重載添刪改

實體類的添刪改操作都可以重載(Insert/Update/Delete/OnInsert/OnUpdate/OnDelete)

重載後可以做業務代碼判斷,也可以級聯更新其它表,還可以記錄添刪改操作日誌,甚至還可以做假刪除(重載OnDelete然後實際執行OnUpdate)

分爲兩組重載,實際執行順序是:Insert=>Valid=>EntityModule=>OnInsert

 

擴展屬性

XCode不支持多表關聯Join,取而代之的是擴展屬性!

擴展屬性的意義,用到該屬性時,再去查詢相應數據,一般目標表帶有緩存,並且擴展屬性Extends也有緩存

一般擴展屬性複雜對象加上XmlIgnore和ScriptIgnore特性,規避Xml序列化和Json序列化。

常常還會加上 AbcName  這樣的字符串型屬性,頭上的Map特性將在魔方NewLife.Cube展現數據時發揮極大作用。

__.ClassID表示映射到該字段,在所有顯示ClassID的地方用當前屬性ClassName替代;

後面的類名和字段名,表示要關聯的目標表和字段,在魔方Cube表單中將直接生成下拉選擇;

 

擴展查詢

實際業務中經常會用到根據某一兩個字段查詢的需求,例如根據主鍵查詢。

一般我們把查詢返回單個對象的方法命名爲 FindByAbc,而把返回多個實體的方法命名爲 FindAllByAbc。

上面的代碼展示了3種查詢方法:

通過Meta.Count判斷,當總行數小於1000時,全部走Meta.Cache實體緩存表達式搜索,其原理是整表一次性載入內存,後續有專門文章介紹;

FindByID和FindByName,當總數大於1000時,走對象緩存Meta.SingleCache,按主鍵ID/Name爲鍵,緩存實體對象;

不常用的FindByMail和FindAllByClassID中,用到了真正的數據庫查詢 Find(__.Mail, mail) 和 FindAll(_.ClassID == classid);

默認生成的代碼,都帶有實體緩存和對象緩存的例子,默認情況下,FindByID只需要查一次數據並載入內存,即可實現“極速查詢”,後續每10秒異步更新。

顯然,如果完全不需要用到緩存,直接寫數據庫代碼就好了。

 

高級查詢

 在業務實現中經常出現超過兩個甚至更多查詢條件,這個時候我們推薦Search或SearchAbc

XCode的查詢有一套條件表達式,以WhereExpression爲代表,可以動態拼接任意複雜的where查詢語句。

FindAll常用兩個參數,第一個條件,第二個PageParameter實現分頁查詢。

 

至此,簡單羅列了實體類的主要構成,具體各個構成部分都將會在後面有專題文章介紹。

 

系列教程

NewLife.XCode教程系列[2019版]

  1. 增刪改查入門。快速展現用法,代碼配置連接字符串
  2. 數據模型文件。建立表格字段和索引,名字以及數據類型規範,推薦字段(時間,用戶,IP)
  3. 實體類詳解。數據類業務類,泛型基類,接口
  4. 功能設置。連接字符串,調試開關,SQL日誌,慢日誌,參數化,執行超時。代碼與配置文件設置,連接字符串局部設置
  5. 反向工程。自動建立數據庫數據表
  6. 數據初始化。InitData寫入初始化數據
  7. 高級增刪改。重載攔截,自增字段,Valid驗證,實體模型(時間,用戶,IP)
  8. 髒數據。如何產生,怎麼利用
  9. 增量累加。高併發統計
  10. 事務處理。單表和多表,不同連接,多種寫法
  11. 擴展屬性。多表關聯,Map映射
  12. 高級查詢。複雜條件,分頁,自定義擴展FieldItem,查總記錄數,查彙總統計
  13. 數據層緩存。Sql緩存,更新機制
  14. 實體緩存。全表整理緩存,更新機制
  15. 對象緩存。字典緩存,適用用戶等數據較多場景。
  16. 百億級性能。字段精煉,索引完備,合理查詢,充分利用緩存
  17. 實體工廠。元數據,通用處理程序
  18. 角色權限。Membership
  19. 導入導出。Xml,Json,二進制,網絡或文件
  20. 分表分庫。常見拆分邏輯
  21. 高級統計。聚合統計,分組統計
  22. 批量寫入。批量插入,批量Upsert,異步保存
  23. 實體隊列。寫入級緩存,提升性能。
  24. 備份同步。備份數據,恢復數據,同步數據
  25. 數據服務。提供RPC接口服務,遠程執行查詢,例如SQLite網絡版
  26. 大數據分析。ETL抽取,調度計算處理,結果持久化

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章