[NewLife.XCode]實(shí)體類詳解
NewLife.XCode是一個(gè)有10多年歷史的開源數(shù)據(jù)中間件,由新生命團(tuán)隊(duì)(2002~2019)開發(fā)完成并維護(hù)至今,以下簡(jiǎn)稱XCode。
整個(gè)系列教程會(huì)大量結(jié)合示例代碼和運(yùn)行日志來進(jìn)行深入分析,蘊(yùn)含多年開發(fā)經(jīng)驗(yàn)于其中。
開源地址:https://github.com/NewLifeX/X (求star, 620+)
生成實(shí)體類
上一章《數(shù)據(jù)模型》講到模型文件Model.xml和腳本Build.tt,(nuget安裝NewLife.XCode后即可擁有)。
把Build.tt和Model.xml(可改名)放在同一個(gè)目錄,在Build.tt上右鍵“運(yùn)行自定義工具”,“顯示所有文件”,即可看到生成的實(shí)體類文件。
**如果運(yùn)行Build.tt出錯(cuò),可能是因?yàn)檎也坏絏Code.dll文件,可以先編譯一次項(xiàng)目,讓XCode.dll生成到項(xiàng)目輸出目錄即可
我們來試試以下模型(拷貝到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="班級(jí)" DbType="SqlServer"> <Columns> <Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="編號(hào)" /> <Column Name="Name" ColumnName="xxx_Nameyyy" DataType="String" Master="True" Description="名稱" /> <Column Name="CreateUser" DataType="String" Description="創(chuàng)建者" /> <Column Name="CreateUserID" DataType="Int32" Description="創(chuàng)建者" /> <Column Name="CreateTime" DataType="DateTime" Description="創(chuàng)建時(shí)間" /> <Column Name="CreateIP" DataType="String" Description="創(chuàng)建地址" /> <Column Name="UpdateUser" DataType="String" Description="更新者" /> <Column Name="UpdateUserID" DataType="Int32" Description="更新者" /> <Column Name="UpdateTime" DataType="DateTime" Description="更新時(shí)間" /> <Column Name="UpdateIP" DataType="String" Description="更新地址" /> <Column Name="Remark" DataType="String" Length="200" Description="備注" /> </Columns> </Table> <Table Name="Student" Description="學(xué)生" DbType="SqlServer"> <Columns> <Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="編號(hào)" /> <Column Name="ClassID" DataType="Int32" Description="班級(jí)" /> <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="手機(jī)" /> <Column Name="Address" DataType="String" Description="地址" /> <Column Name="CreateUserID" DataType="Int32" Description="創(chuàng)建者" /> <Column Name="CreateTime" DataType="DateTime" Description="創(chuàng)建時(shí)間" /> <Column Name="CreateIP" DataType="String" Description="創(chuàng)建地址" /> <Column Name="UpdateUserID" DataType="Int32" Description="更新者" /> <Column Name="UpdateTime" DataType="DateTime" Description="更新時(shí)間" /> <Column Name="UpdateIP" DataType="String" Description="更新地址" /> <Column Name="Remark" DataType="String" Length="200" Description="備注" /> </Columns> <Indexes> <Index Columns="ClassID" /> </Indexes> </Table> </Tables>
運(yùn)行build.tt后

每個(gè)模型表,生成了四個(gè)實(shí)體類文件,選中它們并包含到項(xiàng)目中。
其中Biz常稱之為業(yè)務(wù)類,多次build.tt生成不覆蓋;
另一個(gè)稱之為數(shù)據(jù)類,每次build.tt生成均覆蓋;
這里采用了C#的分部類(partial)技術(shù),一個(gè)類由兩個(gè)或多個(gè)類文件組成。
數(shù)據(jù)類包含表名(類名)字段名(屬性)等信息,修改模型文件后,每次生成都會(huì)覆蓋文件。
業(yè)務(wù)類包含其它非表結(jié)構(gòu)信息,供開發(fā)者填寫代碼,所以只有首次生成,而再次生成時(shí)不會(huì)覆蓋。

數(shù)據(jù)類包括一個(gè)接口(如IStudent),以滿足精簡(jiǎn)需要的場(chǎng)合。
數(shù)據(jù)類內(nèi)部還有兩個(gè)內(nèi)嵌類_和__,可用于快速訪問字段信息以及屬性名。
實(shí)體靜態(tài)構(gòu)造函數(shù)
XCode是充血模型,因此實(shí)體類除了各個(gè)代表著表結(jié)構(gòu)信息的屬性外,還會(huì)有大量用戶代碼在其中,并且繼承泛型實(shí)體基類(如Entity<User>)。
一個(gè)常見的實(shí)體類構(gòu)造函數(shù)如下:
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>(); // 單對(duì)象緩存 var sc = Meta.SingleCache; sc.FindSlaveKeyMethod = k => Find(__.Name, k); sc.GetSlaveKeyMethod = e => e.Name; }
這里首先介紹一個(gè)最重要的實(shí)體類內(nèi)嵌類Meta,它位于Entity<TEntity>.Meta,記錄著實(shí)體類的一切元數(shù)據(jù),承載著實(shí)體類的一切高級(jí)功能!
Meta.Factory.AdditionalFields用于存放累加字段
一般更新語句 update user set Logins=123 where id=1,而把Logins字段設(shè)為累加字段后,將得到 update user set Logins=Logins+33 where id=1 ,特別適用于并發(fā)更新同一行記錄的場(chǎng)合。
實(shí)體過濾器EntityModule,用于攔截實(shí)體類的添刪改操作,內(nèi)置最常用的3個(gè)過濾器UserModule/TimeModule/IPModule
上一章末尾推薦的8個(gè)常用字段還記得嗎? CreateUser/CreateTime/CreateIP 等,所有CreateAbc將在Insert的時(shí)候攔截賦值,所有UpdateAbc將在Insert和Update的時(shí)候攔截賦值。
UserModule取當(dāng)前登錄用戶,由ManageProvider驅(qū)動(dòng);
TimeModule取當(dāng)前時(shí)間;
IPModule取當(dāng)前訪問IP,由ManageProvider.UserHost提供;
緩存配置
單對(duì)象緩存是一個(gè)字典緩存,默認(rèn)以主鍵為key,實(shí)體對(duì)象為value。
單對(duì)象緩存支持第二個(gè)字典,如上,配置Name為第二字典的主鍵,實(shí)體對(duì)象為value。
實(shí)體基類
當(dāng)然,實(shí)體類靜態(tài)構(gòu)造函數(shù)還可以用于其它用途,它將會(huì)在使用該實(shí)體類任意方法(包括成員方法和靜態(tài)方法)之前執(zhí)行。
有時(shí)候把一個(gè)系統(tǒng)模塊放到一個(gè)獨(dú)立子目錄里面,獨(dú)享一個(gè)“Abc.xml”模型文件,生成的實(shí)體類在目錄里面,這個(gè)時(shí)候可以讓它們繼承一個(gè)相同的實(shí)體基類(如EntityBase)。
然后在實(shí)體基類EntityBase的靜態(tài)構(gòu)造函數(shù)中寫入這個(gè)模塊所共有的代碼。
初始化數(shù)據(jù)
有些數(shù)據(jù)表需要默認(rèn)初始化一些數(shù)據(jù),如類別表、配置表等,便于開發(fā)測(cè)試。
這個(gè)時(shí)候可以重載InitData方法,它會(huì)在實(shí)體類第一次訪問數(shù)據(jù)庫(kù)之前執(zhí)行。

這里遇到Meta的第二次用法Meta.Count,該屬性表示當(dāng)前實(shí)體類數(shù)據(jù)表的總行數(shù)。
當(dāng)總行數(shù)在100萬以內(nèi)時(shí),數(shù)字精確等于 select count(*) from table,大于100萬時(shí),將采用特有的快速方法。
Meta.Count帶緩存,擁有極好的性能,可用于粗略(數(shù)值較小時(shí)精確)估算該表總行數(shù)。
這里通過Meta.Count來判斷該表是否為空表,然后對(duì)空表插入一些默認(rèn)數(shù)據(jù)。
數(shù)據(jù)驗(yàn)證Valid
每個(gè)實(shí)體類在Insert/Update之前,都需要Valid驗(yàn)證數(shù)據(jù) ,參數(shù)isNew以區(qū)分Insert。

Valid常常可用于判斷主要字段的有效性,無效時(shí)強(qiáng)烈推薦拋出參數(shù)類異常,魔方NewLife.Cube表單將可以捕獲并定位。
除此之外,Valid用得更多的功能是在Insert/Update之前修改完善字段數(shù)據(jù),例如上面對(duì)密碼進(jìn)行MD5散列,以及格式化RoleIDs。
這里出現(xiàn)新技術(shù),IsDirty和Dirtys,這是XCode的臟數(shù)據(jù),前者判斷Password字段是否有臟數(shù)據(jù)(Password被賦予跟原來不想等的值),后者清空Password臟數(shù)據(jù)。
臟數(shù)據(jù)是生成Update語句的核心,不臟的字段不會(huì)出現(xiàn)在update set 之中,實(shí)現(xiàn)部分字段更新,后續(xù)有專門章節(jié)講解。
重載添刪改
實(shí)體類的添刪改操作都可以重載(Insert/Update/Delete/OnInsert/OnUpdate/OnDelete)


重載后可以做業(yè)務(wù)代碼判斷,也可以級(jí)聯(lián)更新其它表,還可以記錄添刪改操作日志,甚至還可以做假刪除(重載OnDelete然后實(shí)際執(zhí)行OnUpdate)
分為兩組重載,實(shí)際執(zhí)行順序是:Insert=>Valid=>EntityModule=>OnInsert
擴(kuò)展屬性
XCode不支持多表關(guān)聯(lián)Join,取而代之的是擴(kuò)展屬性!
擴(kuò)展屬性的意義,用到該屬性時(shí),再去查詢相應(yīng)數(shù)據(jù),一般目標(biāo)表帶有緩存,并且擴(kuò)展屬性Extends也有緩存

一般擴(kuò)展屬性復(fù)雜對(duì)象加上XmlIgnore和ScriptIgnore特性,規(guī)避Xml序列化和Json序列化。
常常還會(huì)加上 AbcName 這樣的字符串型屬性,頭上的Map特性將在魔方NewLife.Cube展現(xiàn)數(shù)據(jù)時(shí)發(fā)揮極大作用。
__.ClassID表示映射到該字段,在所有顯示ClassID的地方用當(dāng)前屬性ClassName替代;
后面的類名和字段名,表示要關(guān)聯(lián)的目標(biāo)表和字段,在魔方Cube表單中將直接生成下拉選擇;
擴(kuò)展查詢
實(shí)際業(yè)務(wù)中經(jīng)常會(huì)用到根據(jù)某一兩個(gè)字段查詢的需求,例如根據(jù)主鍵查詢。


一般我們把查詢返回單個(gè)對(duì)象的方法命名為 FindByAbc,而把返回多個(gè)實(shí)體的方法命名為 FindAllByAbc。
上面的代碼展示了3種查詢方法:
通過Meta.Count判斷,當(dāng)總行數(shù)小于1000時(shí),全部走M(jìn)eta.Cache實(shí)體緩存表達(dá)式搜索,其原理是整表一次性載入內(nèi)存,后續(xù)有專門文章介紹;
FindByID和FindByName,當(dāng)總數(shù)大于1000時(shí),走對(duì)象緩存Meta.SingleCache,按主鍵ID/Name為鍵,緩存實(shí)體對(duì)象;
不常用的FindByMail和FindAllByClassID中,用到了真正的數(shù)據(jù)庫(kù)查詢 Find(__.Mail, mail) 和 FindAll(_.ClassID == classid);
默認(rèn)生成的代碼,都帶有實(shí)體緩存和對(duì)象緩存的例子,默認(rèn)情況下,F(xiàn)indByID只需要查一次數(shù)據(jù)并載入內(nèi)存,即可實(shí)現(xiàn)“極速查詢”,后續(xù)每10秒異步更新。
顯然,如果完全不需要用到緩存,直接寫數(shù)據(jù)庫(kù)代碼就好了。
高級(jí)查詢
在業(yè)務(wù)實(shí)現(xiàn)中經(jīng)常出現(xiàn)超過兩個(gè)甚至更多查詢條件,這個(gè)時(shí)候我們推薦Search或SearchAbc

XCode的查詢有一套條件表達(dá)式,以WhereExpression為代表,可以動(dòng)態(tài)拼接任意復(fù)雜的where查詢語句。
FindAll常用兩個(gè)參數(shù),第一個(gè)條件,第二個(gè)PageParameter實(shí)現(xiàn)分頁查詢。
至此,簡(jiǎn)單羅列了實(shí)體類的主要構(gòu)成,具體各個(gè)構(gòu)成部分都將會(huì)在后面有專題文章介紹。
系列教程
NewLife.XCode教程系列[2019版]
- 增刪改查入門。快速展現(xiàn)用法,代碼配置連接字符串
- 數(shù)據(jù)模型文件。建立表格字段和索引,名字以及數(shù)據(jù)類型規(guī)范,推薦字段(時(shí)間,用戶,IP)
- 實(shí)體類詳解。數(shù)據(jù)類業(yè)務(wù)類,泛型基類,接口
- 功能設(shè)置。連接字符串,調(diào)試開關(guān),SQL日志,慢日志,參數(shù)化,執(zhí)行超時(shí)。代碼與配置文件設(shè)置,連接字符串局部設(shè)置
- 反向工程。自動(dòng)建立數(shù)據(jù)庫(kù)數(shù)據(jù)表
- 數(shù)據(jù)初始化。InitData寫入初始化數(shù)據(jù)
- 高級(jí)增刪改。重載攔截,自增字段,Valid驗(yàn)證,實(shí)體模型(時(shí)間,用戶,IP)
- 臟數(shù)據(jù)。如何產(chǎn)生,怎么利用
- 增量累加。高并發(fā)統(tǒng)計(jì)
- 事務(wù)處理。單表和多表,不同連接,多種寫法
- 擴(kuò)展屬性。多表關(guān)聯(lián),Map映射
- 高級(jí)查詢。復(fù)雜條件,分頁,自定義擴(kuò)展FieldItem,查總記錄數(shù),查匯總統(tǒng)計(jì)
- 數(shù)據(jù)層緩存。Sql緩存,更新機(jī)制
- 實(shí)體緩存。全表整理緩存,更新機(jī)制
- 對(duì)象緩存。字典緩存,適用用戶等數(shù)據(jù)較多場(chǎng)景。
- 百億級(jí)性能。字段精煉,索引完備,合理查詢,充分利用緩存
- 實(shí)體工廠。元數(shù)據(jù),通用處理程序
- 角色權(quán)限。Membership
- 導(dǎo)入導(dǎo)出。Xml,Json,二進(jìn)制,網(wǎng)絡(luò)或文件
- 分表分庫(kù)。常見拆分邏輯
- 高級(jí)統(tǒng)計(jì)。聚合統(tǒng)計(jì),分組統(tǒng)計(jì)
- 批量寫入。批量插入,批量Upsert,異步保存
- 實(shí)體隊(duì)列。寫入級(jí)緩存,提升性能。
- 備份同步。備份數(shù)據(jù),恢復(fù)數(shù)據(jù),同步數(shù)據(jù)
- 數(shù)據(jù)服務(wù)。提供RPC接口服務(wù),遠(yuǎn)程執(zhí)行查詢,例如SQLite網(wǎng)絡(luò)版
- 大數(shù)據(jù)分析。ETL抽取,調(diào)度計(jì)算處理,結(jié)果持久化

浙公網(wǎng)安備 33010602011771號(hào)