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