国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

基于C#的MongoDB數(shù)據(jù)庫開發(fā)應用(2)--MongoDB數(shù)據(jù)庫的C#開發(fā)

2019-11-14 13:36:02
字體:
來源:轉載
供稿:網(wǎng)友

在上篇博客《基于C#的MongoDB數(shù)據(jù)庫開發(fā)應用(1)--MongoDB數(shù)據(jù)庫的基礎知識和使用》里面,我總結了MongoDB數(shù)據(jù)庫的一些基礎信息,并在最后面部分簡單介紹了數(shù)據(jù)庫C#驅動的開發(fā) ,本文繼續(xù)這個主題,重點介紹MongoDB數(shù)據(jù)庫C#方面的使用和封裝處理過程,利用泛型和基類對象針對數(shù)據(jù)訪問層進行的封裝處理。

前面介紹到,當前2.2版本的數(shù)據(jù)庫C#驅動的API,支持兩種不同的開發(fā)接口,一個是基于MongoDatabase的對象接口,一個是IMongoDatabase的對象接口,前者中規(guī)中矩,和我們使用Shell里面的命令名稱差不多;后者IMongoDatabase的接口是基于異步的,基本上和前者差別很大,而且接口都提供了異步的處理操作。

本文主要介紹基于MongoDatabase的對象接口的封裝處理設置。

1、數(shù)據(jù)訪問層的設計

在結合MongoDB數(shù)據(jù)庫的C#驅動的特點,使用泛型和繼承關系,把常規(guī)的處理接口做了抽象性的封裝,以便封裝適合更多業(yè)務的接口,減少子類代碼及統(tǒng)一API的接口名稱。

首先我們來看看大概的設計思路,我們把實體類抽象一個實體基類,方便使用。

 

我們知道,在MongoDB數(shù)據(jù)庫的集合里面,都要求文檔有一個_id字段,這個是強制性的,而且這個字段的存儲類型為ObjectId類型,這個值考慮了分布式的因素,綜合了機器碼,進程,時間戳等等方面的內容,它的構造如下所示。

ObjectId是一個12字節(jié)的  BSON 類型字符串。按照字節(jié)順序,依次代表:

  • 4字節(jié):UNIX時間戳
  • 3字節(jié):表示運行MongoDB的機器
  • 2字節(jié):表示生成此_id的進程
  • 3字節(jié):由一個隨機數(shù)開始的

    實體基類BaseEntity包含了一個屬性Id,這個是一個字符串型的對象(也可以使用ObjectId類型,但是為了方便,我們使用字符型,并聲明為ObjectId類型即可),由于我們聲明了該屬性對象為ObjectId類型,那么我們就可以在C#代碼里面使用字符串的ID類型了,代碼如下所示。

        /// <summary>    /// MongoDB實體類的基類    /// </summary>    public class BaseEntity    {                /// <summary>        /// 基類對象的ID,MongoDB要求每個實體類必須有的主鍵        /// </summary>        [BsonRePResentation(BsonType.ObjectId)]                public string Id { get; set; }    }

    然后利用泛型的方式,把數(shù)據(jù)訪問層的接口提出來,并引入了數(shù)據(jù)訪問層的基類進行實現(xiàn)和重用接口,如下所示。

    其中,上面幾個類的定義如下所示。

    數(shù)據(jù)訪問層基類BaseDAL的類定義如下所示,主要就是針對上面的IBaseDAL<T>接口進行實現(xiàn)。

    有了這些基類的實現(xiàn),我們對于實體類的處理就非常方便、統(tǒng)一了,基本上不需要在復制大量的代碼來實現(xiàn)基礎的增刪改查分頁實現(xiàn)了。

    例如上面的User集合(表對象)的數(shù)據(jù)訪問類定義如下所示,在對象的定義的時候,指定對應的實體類,并在構造函數(shù)里面指定對應的集合名稱就可以實例化一個數(shù)據(jù)訪問類了。

        /// <summary>    /// 數(shù)據(jù)表User對應的具體數(shù)據(jù)訪問類    /// </summary>    public class User : BaseDAL<UserInfo>, IBaseDAL<UserInfo>    {        /// <summary>        /// 默認構造函數(shù)        /// </summary>        public User()         {            this.entitysName = "users";//對象在數(shù)據(jù)庫的集合名稱        }        .................

    2、基類各種接口的實現(xiàn)

    前面小節(jié)我們介紹了實體基類,數(shù)據(jù)訪問層基類接口和基類實現(xiàn),以及具體集合對象的實現(xiàn)類的定義關系,通過泛型和繼承關系,我們很好的抽象了各種對象的增刪改查、分頁等操作,子類繼承了BaseDAL基類后,就自然而然的具有了非常強大的接口處理功能了。下面我們來繼續(xù)詳細介紹基于C#驅動的MongoDB數(shù)據(jù)庫是如何進行各種增刪改查等封裝的。

    1)構造MongoDatabase對象

    首先我們需要利用連接字符串來構建MongoDatabase對象,因為所有的接口都是基于這個對象進行處理的,代碼如下所示。

            /// <summary>        /// 根據(jù)數(shù)據(jù)庫配置信息創(chuàng)建MongoDatabase對象,如果不指定配置信息,則從默認信息創(chuàng)建        /// </summary>        /// <param name="databaseName">數(shù)據(jù)庫名稱,默認空為local</param>        /// <returns></returns>        protected virtual MongoDatabase CreateDatabase()        {            string connectionString = null;            if (!string.IsNullOrEmpty(dbConfigName))            {                //從配置文件中獲取對應的連接信息                connectionString = ConfigurationManager.ConnectionStrings[dbConfigName].ConnectionString;                            }            else            {                connectionString = defaultConnectionString;            }            var client = new MongoClient(connectionString);            var database = client.GetServer().GetDatabase(new MongoUrl(connectionString).DatabaseName);            return database;        }

    2)構建MongoCollection對象

    上面構建了MongoDatabase對象后,我們需要基于這個基礎上再創(chuàng)建一個對象的MongoCollection對象,這個就是類似我們關系數(shù)據(jù)庫里面的表對象的原型了。

            /// <summary>        /// 獲取操作對象的MongoCollection集合,強類型對象集合        /// </summary>        /// <returns></returns>        protected virtual MongoCollection<T> GetCollection()        {            MongoDatabase database = CreateDatabase();            return database.GetCollection<T>(this.entitysName);        }

    3)查詢單個對象

    利用MongoCollection對象,我們可以通過API接口獲取對應的對象,單個對象的接口為FindOneById(也可以用FindOne接口,如注釋部分的代碼),我們具體的處理代碼如下所示

            /// <summary>        /// 查詢數(shù)據(jù)庫,檢查是否存在指定ID的對象        /// </summary>        /// <param name="key">對象的ID值</param>        /// <returns>存在則返回指定的對象,否則返回Null</returns>        public virtual T FindByID(string id)        {            ArgumentValidation.CheckForEmptyString(id, "傳入的對象id為空");            MongoCollection<T> collection = GetCollection();            return collection.FindOneById(new ObjectId(id)); //FindOne(Query.EQ("_id", new ObjectId(id)));        }

    如果基于條件的單個記錄查詢,我們可以使用Expression<Func<T, bool>>和IMongoQuery的參數(shù)進行處理,如下代碼所示。

            /// <summary>        /// 根據(jù)條件查詢數(shù)據(jù)庫,如果存在返回第一個對象        /// </summary>        /// <param name="match">條件表達式</param>        /// <returns>存在則返回指定的第一個對象,否則返回默認值</returns>        public virtual T FindSingle(Expression<Func<T, bool>> match)        {            MongoCollection<T> collection = GetCollection();            return collection.AsQueryable().Where(match).FirstOrDefault();        }        /// <summary>        /// 根據(jù)條件查詢數(shù)據(jù)庫,如果存在返回第一個對象        /// </summary>        /// <param name="query">條件表達式</param>        /// <returns>存在則返回指定的第一個對象,否則返回默認值</returns>        public virtual T FindSingle(IMongoQuery query)        {            MongoCollection<T> collection = GetCollection();            return collection.FindOne(query);        } 

    4)IQueryable的接口利用

    使用過EF的實體框架的話,我們對其中的IQueryable<T>印象很深刻,它可以給我提供很好的LINQ語法獲取對應的信息,它可以通過使用Expression<Func<T, bool>>和IMongoQuery的參數(shù)來進行條件的查詢操作,MongoCollection對象有一個AsQueryable()的API進行轉換,如下所示。

            /// <summary>        /// 返回可查詢的記錄源        /// </summary>        /// <returns></returns>        public virtual IQueryable<T> GetQueryable()        {            MongoCollection<T> collection = GetCollection();            IQueryable<T> query = collection.AsQueryable();            return query.OrderBy(this.SortPropertyName, this.IsDescending);        }

    如果是通過使用Expression<Func<T, bool>>和IMongoQuery的參數(shù),那么處理的接口代碼如下所示。

            /// <summary>        /// 根據(jù)條件表達式返回可查詢的記錄源        /// </summary>        /// <param name="match">查詢條件</param>        /// <param name="sortPropertyName">排序表達式</param>        /// <param name="isDescending">如果為true則為降序,否則為升序</param>        /// <returns></returns>        public virtual IQueryable<T> GetQueryable(Expression<Func<T, bool>> match, string sortPropertyName, bool isDescending = true)        {            MongoCollection<T> collection = GetCollection();            IQueryable<T> query = collection.AsQueryable();            if (match != null)            {                query = query.Where(match);            }            return query.OrderBy(sortPropertyName, isDescending);        }
            /// <summary>        /// 根據(jù)條件表達式返回可查詢的記錄源        /// </summary>        /// <param name="query">查詢條件</param>        /// <param name="sortPropertyName">排序表達式</param>        /// <param name="isDescending">如果為true則為降序,否則為升序</param>        /// <returns></returns>        public virtual IQueryable<T> GetQueryable(IMongoQuery query, string sortPropertyName, bool isDescending = true)        {            MongoCollection<T> collection = GetCollection();            IQueryable<T> queryable = collection.Find(query).AsQueryable();            return queryable.OrderBy(sortPropertyName, isDescending);        }

    5)集合的查詢處理

    通過利用上面的IQueryable<T>對象,以及使用Expression<Func<T, bool>>和IMongoQuery的參數(shù),我們很好的進行集合的查詢處理操作的了,具體代碼如下所示

            /// <summary>        /// 根據(jù)條件查詢數(shù)據(jù)庫,并返回對象集合        /// </summary>        /// <param name="match">條件表達式</param>        /// <returns>指定對象的集合</returns>        public virtual IList<T> Find(Expression<Func<T, bool>> match)        {            return GetQueryable(match).ToList();        }        /// <summary>        /// 根據(jù)條件查詢數(shù)據(jù)庫,并返回對象集合        /// </summary>        /// <param name="query">條件表達式</param>        /// <returns>指定對象的集合</returns>        public virtual IList<T> Find(IMongoQuery query)        {            MongoCollection<T> collection = GetCollection();            return collection.Find(query).ToList();        }

    對于分頁,我們是非常需要的,首先在大數(shù)據(jù)的集合里面,我們不可能一股腦的把所有的數(shù)據(jù)全部返回,因此根據(jù)分頁參數(shù)返回有限數(shù)量的集合處理就是我們應該做的,分頁的操作代碼和上面很類似,只是利用了Skip和Take的接口,返回我們需要的記錄數(shù)量就可以了。

            /// <summary>        /// 根據(jù)條件查詢數(shù)據(jù)庫,并返回對象集合(用于分頁數(shù)據(jù)顯示)        /// </summary>        /// <param name="match">條件表達式</param>        /// <param name="info">分頁實體</param>        /// <returns>指定對象的集合</returns>        public virtual IList<T> FindWithPager(Expression<Func<T, bool>> match, PagerInfo info)        {            int pageindex = (info.CurrenetPageIndex < 1) ? 1 : info.CurrenetPageIndex;            int pageSize = (info.PageSize <= 0) ? 20 : info.PageSize;            int excludedRows = (pageindex - 1) * pageSize;            IQueryable<T> query = GetQueryable(match);            info.RecordCount = query.Count();            return query.Skip(excludedRows).Take(pageSize).ToList();        }

    或者是下面的代碼

            /// <summary>        /// 根據(jù)條件查詢數(shù)據(jù)庫,并返回對象集合(用于分頁數(shù)據(jù)顯示)        /// </summary>        /// <param name="query">條件表達式</param>        /// <param name="info">分頁實體</param>        /// <returns>指定對象的集合</returns>        public virtual IList<T> FindWithPager(IMongoQuery query, PagerInfo info)        {            int pageindex = (info.CurrenetPageIndex < 1) ? 1 : info.CurrenetPageIndex;            int pageSize = (info.PageSize <= 0) ? 20 : info.PageSize;            int excludedRows = (pageindex - 1) * pageSize;            IQueryable<T> queryable = GetQueryable(query);            info.RecordCount = queryable.Count();            return queryable.Skip(excludedRows).Take(pageSize).ToList();        }

    6)對象的寫入操作

    對象的寫入可以使用save,它是根據(jù)_id的來決定插入還是更新的,如下代碼所示。

            /// <summary>        /// 保存指定對象到數(shù)據(jù)庫中,根據(jù)Id的值,決定是插入還是更新        /// </summary>        /// <param name="t">指定的對象</param>        /// <returns>執(zhí)行成功指定對象信息</returns>        public virtual T Save(T t)        {            ArgumentValidation.CheckForNullReference(t, "傳入的對象t為空");            MongoCollection<T> collection = GetCollection();            var result = collection.Save(t);            return t;        }

    插入記錄就可以利用insert方法進行處理的,代碼如下所示。

            /// <summary>        /// 插入指定對象到數(shù)據(jù)庫中        /// </summary>        /// <param name="t">指定的對象</param>        /// <returns>執(zhí)行成功返回<c>true</c>,否則為<c>false</c></returns>        public virtual bool Insert(T t)        {            ArgumentValidation.CheckForNullReference(t, "傳入的對象t為空");            MongoCollection<T> collection = GetCollection();            var result = collection.Insert(t);            return result != null && result.DocumentsAffected > 0;        }

    如果是批量插入,可以利用它的insertBatch的方法進行處理,具體代碼如下所示。

            /// <summary>        /// 插入指定對象集合到數(shù)據(jù)庫中        /// </summary>        /// <param name="list">指定的對象集合</param>        /// <returns>執(zhí)行成功返回<c>true</c>,否則為<c>false</c></returns>        public virtual bool InsertBatch(IEnumerable<T> list)        {            ArgumentValidation.CheckForNullReference(list, "傳入的對象list為空");            MongoCollection<T> collection = GetCollection();            var result = collection.InsertBatch(list);            return result.Any(s => s != null && s.DocumentsAffected > 0); //部分成功也返回true        }

    7)對象的更新操作

    更新操作分為了兩個不同的部分,一個是全部的記錄更新,也就是整個JSON的替換操作了,一般我們是在原來的基礎上進行更新的,如下代碼所示。

            /// <summary>        /// 更新對象屬性到數(shù)據(jù)庫中        /// </summary>        /// <param name="t">指定的對象</param>        /// <param name="id">主鍵的值</param>        /// <returns>執(zhí)行成功返回<c>true</c>,否則為<c>false</c></returns>        public virtual bool Update(T t, string id)        {            ArgumentValidation.CheckForNullReference(t, "傳入的對象t為空");            ArgumentValidation.CheckForEmptyString(id, "傳入的對象id為空");            bool result = false;            MongoCollection<T> collection = GetCollection();            var existing = FindByID(id);            if (existing != null)            {                var resultTmp = collection.Save(t);                result = resultTmp != null && resultTmp.DocumentsAffected > 0;            }            return result;        }

    還有一種方式是部分更新,也就是更新里面的指定一個或幾個字段,不會影響其他字段,也就不會全部替換掉其他內容的操作了。這里利用了一個UpdateBuilder<T>的對象,用來指定那些字段需要更新,以及這些字段的值內容的,具體的更新代碼如下所示。

            /// <summary>        /// 封裝處理更新的操作        /// </summary>        /// <param name="id">主鍵的值</param>        /// <param name="update">更新對象</param>        /// <returns>執(zhí)行成功返回<c>true</c>,否則為<c>false</c></returns>        public virtual bool Update(string id, UpdateBuilder<T> update)        {            ArgumentValidation.CheckForNullReference(update, "傳入的對象update為空");            ArgumentValidation.CheckForEmptyString(id, "傳入的對象id為空");            var query = Query.EQ("_id", new ObjectId(id));            MongoCollection<T> collection = GetCollection();            var result = collection.Update(query, update);            return result != null && result.DocumentsAffected > 0;        }

    部分更新,可以結合使用Inc和Set方法來進行處理,如下是我在子類里面利用到上面的Update部分更新的API進行處理個別字段的更新操作。

            /// <summary>        /// 為用戶增加歲數(shù)        /// </summary>        /// <param name="id">記錄ID</param>        /// <param name="addAge">待增加的歲數(shù)</param>        /// <returns></returns>        public bool IncreaseAge(string id, int addAge)        {            //增加指定的歲數(shù)            var query = Query<UserInfo>.EQ(s => s.Id, id);            var update = Update<UserInfo>.Inc(s => s.Age, addAge);            var collection = GetCollection();            var result = collection.Update(query, update);            return result != null && result.DocumentsAffected > 0;        }        /// <summary>        /// 單獨修改用戶的名稱        /// </summary>        /// <param name="id">記錄ID</param>        /// <param name="newName">用戶新名稱</param>        /// <returns></returns>        public bool UpdateName(string id, string newName)        {            //增加指定的歲數(shù)            var query = Query<UserInfo>.EQ(s => s.Id, id);            var update = Update<UserInfo>.Set(s => s.Name, newName);            var collection = GetCollection();            var result = collection.Update(query, update);            return result != null && result.DocumentsAffected > 0;        }

    8)對象的刪除操作

    對象的刪除,一般可以利用條件進行刪除,如單個刪除可以使用_id屬性進行處理,也可以利用批量刪除的接口進行刪除操作,代碼如下所示。

            /// <summary>        /// 根據(jù)指定對象的ID,從數(shù)據(jù)庫中刪除指定對象        /// </summary>        /// <param name="id">對象的ID</param>        /// <returns>執(zhí)行成功返回<c>true</c>,否則為<c>false</c></returns>        public virtual bool Delete(string id)        {            ArgumentValidation.CheckForEmptyString(id, "傳入的對象id為空");            MongoCollection<T> collection = GetCollection();            //var result = collection.Remove(Query<T>.EQ(s => s.Id, id));            var result = collection.Remove(Query.EQ("_id", new ObjectId(id)));            return result != null && result.DocumentsAffected > 0;        }

    其中上面注釋的var result = collection.Remove(Query<T>.EQ(s => s.Id, id));代碼,就是利用了強類型的對象屬性和值進行移除,一樣可以的。

    對于批量刪除,可以利用Query的不同進行處理。

            /// <summary>        /// 根據(jù)指定對象的ID,從數(shù)據(jù)庫中刪除指定指定的對象        /// </summary>        /// <param name="idList">對象的ID集合</param>        /// <returns>執(zhí)行成功返回<c>true</c>,否則為<c>false</c></returns>        public virtual bool DeleteBatch(List<string> idList)        {            ArgumentValidation.CheckForNullReference(idList, "傳入的對象idList為空");            MongoCollection<T> collection = GetCollection();            var query = Query.In("_id", new BsonArray(idList));            var result = collection.Remove(query);            return result != null && result.DocumentsAffected > 0;        }

    或者基于IMongoQuery的條件進行處理。

            /// <summary>        /// 根據(jù)指定條件,從數(shù)據(jù)庫中刪除指定對象        /// </summary>        /// <param name="match">條件表達式</param>        /// <returns>執(zhí)行成功返回<c>true</c>,否則為<c>false</c></returns>        public virtual bool DeleteByQuery(IMongoQuery query)        {            MongoCollection<T> collection = GetCollection();            var result = collection.Remove(query);            return result != null && result.DocumentsAffected > 0;        } 

    9)其他相關接口

    一般除了上面的接口,還有一些其他的接口,如獲取記錄的總數(shù)、判斷條件的記錄是否存在等也是很常見的,他們的代碼封裝如下所示。

            /// <summary>        /// 獲取表的所有記錄數(shù)量        /// </summary>        /// <returns></returns>        public virtual int GetRecordCount()        {            return GetQueryable().Count();        }
            /// <summary>        /// 根據(jù)查詢條件,判斷是否存在記錄        /// </summary>        /// <param name="match">條件表達式</param>        /// <returns></returns>        public virtual bool IsExistRecord(Expression<Func<T, bool>> match)        {            return GetQueryable(match).Any();//.Count() > 0        }        /// <summary>        /// 根據(jù)查詢條件,判斷是否存在記錄        /// </summary>        /// <param name="query">條件表達式</param>        /// <returns></returns>        public virtual bool IsExistRecord(IMongoQuery query)        {            return GetQueryable(query).Any();//.Count() > 0        }

     

    非常感謝您的詳細閱讀,以上基本上就是我對整個MongoDB數(shù)據(jù)庫的各個接口的基類封裝處理了,其中已經(jīng)覆蓋到了基礎的增刪改查、分頁等操作接口,以及一些特殊的條件處理接口的擴展,我們利用這些封裝好的基類很好的簡化了子類的代碼,而且可以更方便的在基類的基礎上進行特殊功能的擴展處理。

    當然,以上介紹的都不是最新的接口,是2.0(或2.2)版本之前的接口實現(xiàn),雖然在2.2里面也還可以利用上面的MongoDatabase對象接口,但是IMongoDatabase最新的接口已經(jīng)全面兼容異步的操作,但也是一個很大的跳躍,基本上引入了不同的接口命名和處理方式,利用異步可以支持更好的處理體驗,但是也基本上是需要對所有的接口進行了全部的重寫了。

    下一篇我會專門介紹一下基于最新的異步接口如何實現(xiàn)這些常規(guī)增刪改查、分頁等的基類實現(xiàn)封裝處理。

     


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 忻城县| 雷州市| 铜川市| 扶余县| 麻城市| 西华县| 正镶白旗| 肃南| 五莲县| 大港区| 吉首市| 西宁市| 嘉鱼县| 阿合奇县| 长葛市| 柘城县| 台州市| 祁门县| 福鼎市| 滁州市| 专栏| 遂宁市| 老河口市| 青州市| 泰州市| 阜康市| 西充县| 洮南市| 宜州市| 临汾市| 年辖:市辖区| 连云港市| 济源市| 文昌市| 仪陇县| 肇东市| 潞城市| 花莲县| 合作市| 沅陵县| 观塘区|