在上篇部落格《基于C#的MongoDB資料庫開發應用(1)--MongoDB資料庫的基礎知識和使用》裡面,我總結了MongoDB資料庫的一些基礎資訊,并在最後面部分簡單介紹了資料庫C#驅動的開發 ,本文繼續這個主題,重點介紹MongoDB資料庫C#方面的使用和封裝處理過程,利用泛型和基類對象針對資料通路層進行的封裝處理。
前面介紹到,目前2.2版本的資料庫C#驅動的API,支援兩種不同的開發接口,一個是基于MongoDatabase的對象接口,一個是IMongoDatabase的對象接口,前者中規中矩,和我們使用Shell裡面的指令名稱差不多;後者IMongoDatabase的接口是基于異步的,基本上和前者差别很大,而且接口都提供了異步的處理操作。
本文主要介紹基于MongoDatabase的對象接口的封裝處理設定。
在結合MongoDB資料庫的C#驅動的特點,使用泛型和繼承關系,把正常的處理接口做了抽象性的封裝,以便封裝适合更多業務的接口,減少子類代碼及統一API的接口名稱。
首先我們來看看大概的設計思路,我們把實體類抽象一個實體基類,友善使用。

我們知道,在MongoDB資料庫的集合裡面,都要求文檔有一個_id字段,這個是強制性的,而且這個字段的存儲類型為ObjectId類型,這個值考慮了分布式的因素,綜合了機器碼,程序,時間戳等等方面的内容,它的構造如下所示。
ObjectId是一個12位元組的 BSON 類型字元串。按照位元組順序,依次代表:
4位元組:UNIX時間戳
3位元組:表示運作MongoDB的機器
2位元組:表示生成此_id的程序
3位元組:由一個随機數開始的計數器生成的值
實體基類BaseEntity包含了一個屬性Id,這個是一個字元串型的對象(也可以使用ObjectId類型,但是為了友善,我們使用字元型,并聲明為ObjectId類型即可),由于我們聲明了該屬性對象為ObjectId類型,那麼我們就可以在C#代碼裡面使用字元串的ID類型了,代碼如下所示。
然後利用泛型的方式,把資料通路層的接口提出來,并引入了資料通路層的基類進行實作和重用接口,如下所示。
其中,上面幾個類的定義如下所示。
資料通路層基類BaseDAL的類定義如下所示,主要就是針對上面的IBaseDAL<T>接口進行實作。
有了這些基類的實作,我們對于實體類的處理就非常友善、統一了,基本上不需要在複制大量的代碼來實作基礎的增删改查分頁實作了。
例如上面的User集合(表對象)的資料通路類定義如下所示,在對象的定義的時候,指定對應的實體類,并在構造函數裡面指定對應的集合名稱就可以執行個體化一個資料通路類了。
前面小節我們介紹了實體基類,資料通路層基類接口和基類實作,以及具體集合對象的實作類的定義關系,通過泛型和繼承關系,我們很好的抽象了各種對象的增删改查、分頁等操作,子類繼承了BaseDAL基類後,就自然而然的具有了非常強大的接口處理功能了。下面我們來繼續詳細介紹基于C#驅動的MongoDB資料庫是如何進行各種增删改查等封裝的。
1)構造MongoDatabase對象
首先我們需要利用連接配接字元串來建構MongoDatabase對象,因為所有的接口都是基于這個對象進行處理的,代碼如下所示。
2)建構MongoCollection對象
上面建構了MongoDatabase對象後,我們需要基于這個基礎上再建立一個對象的MongoCollection對象,這個就是類似我們關系資料庫裡面的表對象的原型了。
3)查詢單個對象
利用MongoCollection對象,我們可以通過API接口擷取對應的對象,單個對象的接口為FindOneById(也可以用FindOne接口,如注釋部分的代碼),我們具體的處理代碼如下所示
如果基于條件的單個記錄查詢,我們可以使用Expression<Func<T, bool>>和IMongoQuery的參數進行處理,如下代碼所示。
4)IQueryable的接口利用
使用過EF的實體架構的話,我們對其中的IQueryable<T>印象很深刻,它可以給我提供很好的LINQ文法擷取對應的資訊,它可以通過使用Expression<Func<T, bool>>和IMongoQuery的參數來進行條件的查詢操作,MongoCollection對象有一個AsQueryable()的API進行轉換,如下所示。
如果是通過使用Expression<Func<T, bool>>和IMongoQuery的參數,那麼處理的接口代碼如下所示。
5)集合的查詢處理
通過利用上面的IQueryable<T>對象,以及使用Expression<Func<T, bool>>和IMongoQuery的參數,我們很好的進行集合的查詢處理操作的了,具體代碼如下所示
對于分頁,我們是非常需要的,首先在大資料的集合裡面,我們不可能一股腦的把所有的資料全部傳回,是以根據分頁參數傳回有限數量的集合處理就是我們應該做的,分頁的操作代碼和上面很類似,隻是利用了Skip和Take的接口,傳回我們需要的記錄數量就可以了。
或者是下面的代碼
6)對象的寫入操作
對象的寫入可以使用save,它是根據_id的來決定插入還是更新的,如下代碼所示。
插入記錄就可以利用insert方法進行處理的,代碼如下所示。
如果是批量插入,可以利用它的insertBatch的方法進行處理,具體代碼如下所示。
7)對象的更新操作
更新操作分為了兩個不同的部分,一個是全部的記錄更新,也就是整個JSON的替換操作了,一般我們是在原來的基礎上進行更新的,如下代碼所示。
還有一種方式是部分更新,也就是更新裡面的指定一個或幾個字段,不會影響其他字段,也就不會全部替換掉其他内容的操作了。這裡利用了一個UpdateBuilder<T>的對象,用來指定那些字段需要更新,以及這些字段的值内容的,具體的更新代碼如下所示。
部分更新,可以結合使用Inc和Set方法來進行處理,如下是我在子類裡面利用到上面的Update部分更新的API進行處理個别字段的更新操作。
8)對象的删除操作
對象的删除,一般可以利用條件進行删除,如單個删除可以使用_id屬性進行處理,也可以利用批量删除的接口進行删除操作,代碼如下所示。
其中上面注釋的var result = collection.Remove(Query<T>.EQ(s => s.Id, id));代碼,就是利用了強類型的對象屬性和值進行移除,一樣可以的。
對于批量删除,可以利用Query的不同進行處理。
或者基于IMongoQuery的條件進行處理。
9)其他相關接口
一般除了上面的接口,還有一些其他的接口,如擷取記錄的總數、判斷條件的記錄是否存在等也是很常見的,他們的代碼封裝如下所示。
非常感謝您的詳細閱讀,以上基本上就是我對整個MongoDB資料庫的各個接口的基類封裝處理了,其中已經覆寫到了基礎的增删改查、分頁等操作接口,以及一些特殊的條件處理接口的擴充,我們利用這些封裝好的基類很好的簡化了子類的代碼,而且可以更友善的在基類的基礎上進行特殊功能的擴充處理。
當然,以上介紹的都不是最新的接口,是2.0(或2.2)版本之前的接口實作,雖然在2.2裡面也還可以利用上面的MongoDatabase對象接口,但是IMongoDatabase最新的接口已經全面相容異步的操作,但也是一個很大的跳躍,基本上引入了不同的接口命名和處理方式,利用異步可以支援更好的處理體驗,但是也基本上是需要對所有的接口進行了全部的重寫了。
下一篇我會專門介紹一下基于最新的異步接口如何實作這些正常增删改查、分頁等的基類實作封裝處理。