基于C#的MongoDB數(shù)據(jù)庫(kù)開(kāi)發(fā)應(yīng)用(3)--MongoDB數(shù)據(jù)庫(kù)的C#開(kāi)發(fā)之異步接口

在前面的系列博客中肢扯,我曾經(jīng)介紹過(guò)妒茬,MongoDB數(shù)據(jù)庫(kù)的C#驅(qū)動(dòng)已經(jīng)全面支持異步的處理接口,并且接口的定義幾乎是重寫(xiě)了蔚晨。本篇主要介紹MongoDB數(shù)據(jù)庫(kù)的C#驅(qū)動(dòng)的最新接口使用乍钻,介紹基于新接口如何實(shí)現(xiàn)基礎(chǔ)的增刪改查及分頁(yè)等處理,以及如何利用異步接口實(shí)現(xiàn)基類(lèi)相關(guān)的異步操作铭腕。

MongoDB數(shù)據(jù)庫(kù)驅(qū)動(dòng)在2.2版本(或者是從2.0開(kāi)始)好像完全改寫(xiě)了API的接口团赁,因此目前這個(gè)版本同時(shí)支持兩個(gè)版本的API處理,一個(gè)是基于MongoDatabase的對(duì)象接口谨履,一個(gè)是IMongoDatabase的對(duì)象接口,前者中規(guī)中矩熬丧,和我們使用Shell里面的命令名稱(chēng)差不多笋粟,后者IMongoDatabase的接口是基于異步的,基本上和前者差別很大析蝴,而且接口都提供了異步的處理操作害捕。

1、MongoDB數(shù)據(jù)庫(kù)C#驅(qū)動(dòng)的新接口

新接口也還是基于數(shù)據(jù)庫(kù)闷畸,集合尝盼,文檔這樣的處理概念進(jìn)行封裝,只是它們的接口不再一樣了佑菩,我們還是按照前面的做法盾沫,定義一個(gè)數(shù)據(jù)庫(kù)訪問(wèn)的基類(lèi)裁赠,對(duì)MongoDB數(shù)據(jù)庫(kù)的相關(guān)操作封裝在基類(lèi)里面,方便使用赴精,同時(shí)基類(lèi)利用泛型對(duì)象佩捞,實(shí)現(xiàn)更強(qiáng)類(lèi)型的約束及支持,如基類(lèi)BaseDAL的定義如下所示蕾哟。

/// <summary>
/// 數(shù)據(jù)訪問(wèn)層的基類(lèi)
/// </summary>
public partial class BaseDAL<T> where T : BaseEntity, new()

利用泛型的方式一忱,把數(shù)據(jù)訪問(wèn)層的接口提出來(lái),并引入了數(shù)據(jù)訪問(wèn)層的基類(lèi)進(jìn)行實(shí)現(xiàn)和重用接口谭确,如下所示帘营。




基于新接口,如獲取數(shù)據(jù)庫(kù)對(duì)象的操作逐哈,則利用了IMongoDatabase的接口了芬迄,如下所示。

var client = new MongoClient(connectionString);
var database = client.GetDatabase(new MongoUrl(connectionString).DatabaseName);

相對(duì)以前的常規(guī)接口鞠眉,MongoClient對(duì)象已經(jīng)沒(méi)有了GetServer的接口了薯鼠。如果對(duì)創(chuàng)建數(shù)據(jù)庫(kù)對(duì)象的操作做更好的封裝,可以利用配置文件進(jìn)行指定的話械蹋,那么方法可以封裝如下所示出皇。

/// <summary>
/// 根據(jù)數(shù)據(jù)庫(kù)配置信息創(chuàng)建MongoDatabase對(duì)象,如果不指定配置信息哗戈,則從默認(rèn)信息創(chuàng)建
/// </summary>
/// <param name="databaseName">數(shù)據(jù)庫(kù)名稱(chēng)郊艘,默認(rèn)空為local</param>
/// <returns></returns>
protected virtual IMongoDatabase CreateDatabase()
{
    string connectionString = null;
    if (!string.IsNullOrEmpty(dbConfigName))
    {
        //從配置文件中獲取對(duì)應(yīng)的連接信息
        connectionString = ConfigurationManager.ConnectionStrings[dbConfigName].ConnectionString;                
    }
    else
    {
        connectionString = defaultConnectionString;
    }

    var client = new MongoClient(connectionString);
    var database = client.GetDatabase(new MongoUrl(connectionString).DatabaseName);

    return database;
}

根據(jù)IMongoDatabase 接口,那么其獲取集合對(duì)象的操作如下所示唯咬,它使用了另外一個(gè)定義IMongoCollection了纱注。

/// <summary>
/// 獲取操作對(duì)象的IMongoCollection集合,強(qiáng)類(lèi)型對(duì)象集合
/// </summary>
/// <returns></returns>
public virtual IMongoCollection<T> GetCollection()
{
    var database = CreateDatabase();
    return database.GetCollection<T>(this.entitysName);
}

2、查詢(xún)單個(gè)對(duì)象實(shí)現(xiàn)封裝處理

基于新接口的查詢(xún)處理胆胰,已經(jīng)沒(méi)有FindOne的方法定義了狞贱,只是使用了Find的方法,而且也沒(méi)有了Query的對(duì)象可以作為條件進(jìn)行處理蜀涨,而是采用了新的定義對(duì)象FilterDefinition瞎嬉,例如對(duì)于根據(jù)ID查詢(xún)單個(gè)對(duì)象,接口的實(shí)現(xiàn)如下所示厚柳。

/// <summary>
/// 查詢(xún)數(shù)據(jù)庫(kù),檢查是否存在指定ID的對(duì)象
/// </summary>
/// <param name="key">對(duì)象的ID值</param>
/// <returns>存在則返回指定的對(duì)象,否則返回Null</returns>
public virtual T FindByID(string id)
{
    ArgumentValidation.CheckForEmptyString(id, "傳入的對(duì)象id為空");

    IMongoCollection<T> collection = GetCollection();
    return collection.Find(s=> s.Id == id).FirstOrDefault();
}

對(duì)于利用FilterDefinition進(jìn)行查詢(xún)的操作氧枣,如下所示。

/// <summary>
/// 根據(jù)條件查詢(xún)數(shù)據(jù)庫(kù),如果存在返回第一個(gè)對(duì)象
/// </summary>
/// <param name="filter">條件表達(dá)式</param>
/// <returns>存在則返回指定的第一個(gè)對(duì)象,否則返回默認(rèn)值</returns>
public virtual T FindSingle(FilterDefinition<T> filter)
{
    IMongoCollection<T> collection = GetCollection();
    return collection.Find(filter).FirstOrDefault();
} 

我們可以看到别垮,這些都是利用Find方法的不同重載實(shí)現(xiàn)不同條件的處理的便监。

對(duì)于這個(gè)新接口,異步是一個(gè)重要的改變碳想,那么它的異步處理是如何的呢烧董,我們看看上面兩個(gè)異步的實(shí)現(xiàn)操作毁靶,具體代碼如下所示。

/// <summary>
/// 查詢(xún)數(shù)據(jù)庫(kù),檢查是否存在指定ID的對(duì)象(異步)
/// </summary>
/// <param name="key">對(duì)象的ID值</param>
/// <returns>存在則返回指定的對(duì)象,否則返回Null</returns>
public virtual async Task<T> FindByIDAsync(string id)
{
    ArgumentValidation.CheckForEmptyString(id, "傳入的對(duì)象id為空");

    IMongoCollection<T> collection = GetCollection();
    return await collection.FindAsync(s=>s.Id == id).Result.FirstOrDefaultAsync(); 
}

/// <summary>
/// 根據(jù)條件查詢(xún)數(shù)據(jù)庫(kù),如果存在返回第一個(gè)對(duì)象(異步)
/// </summary>
/// <param name="query">條件表達(dá)式</param>
/// <returns>存在則返回指定的第一個(gè)對(duì)象,否則返回默認(rèn)值</returns>
public virtual async Task<T> FindSingleAsync(FilterDefinition<T> query)
{
    return await GetQueryable(query).SingleOrDefaultAsync();
}

我們看到解藻,上面的Collection或者GetQueryable(query)返回的對(duì)象老充,都提供給了以Async結(jié)尾的異步方法,因此對(duì)異步的封裝也是非常方便的螟左,上面的GetQueryable(query)是另外一個(gè)公共的實(shí)現(xiàn)方法啡浊,具體代碼如下所示。

/// <summary>
/// 返回可查詢(xún)的記錄源
/// </summary>
/// <param name="query">查詢(xún)條件</param>
/// <returns></returns>
public virtual IFindFluent<T, T> GetQueryable(FilterDefinition<T> query)
{
    return GetQueryable(query, this.SortPropertyName, this.IsDescending);
}
/// <summary>
/// 根據(jù)條件表達(dá)式返回可查詢(xún)的記錄源
/// </summary>
/// <param name="query">查詢(xún)條件</param>
/// <param name="sortPropertyName">排序表達(dá)式</param>
/// <param name="isDescending">如果為true則為降序胶背,否則為升序</param>
/// <returns></returns>
public virtual IFindFluent<T,T> GetQueryable(FilterDefinition<T> query, string sortPropertyName, bool isDescending = true)
{
    IMongoCollection<T> collection = GetCollection();
    IFindFluent<T, T> queryable = collection.Find(query);

    var sort = this.IsDescending ? Builders<T>.Sort.Descending(this.SortPropertyName) : Builders<T>.Sort.Ascending(this.SortPropertyName);
    return queryable.Sort(sort);
}

我們可以看到巷嚣,它返回了IFindFluent<T, T>的對(duì)象,這個(gè)和以前返回的IMongoQuery對(duì)象又有不同钳吟,基本上廷粒,使用最新的接口,所有的實(shí)現(xiàn)都不太一樣红且,這也是因?yàn)镸ongoDB還在不停變化之中有關(guān)坝茎。

3、GetQueryable幾種方式

為了簡(jiǎn)化代碼暇番,方便使用嗤放,我們對(duì)獲取MongoDB的LINQ方式的處理做了簡(jiǎn)單的封裝,提供了幾個(gè)GetQueryable的方式壁酬,具體代碼如下所示次酌。

/// <summary>
/// 返回可查詢(xún)的記錄源
/// </summary>
/// <returns></returns>
public virtual IQueryable<T> GetQueryable()
{
    IMongoCollection<T> collection = GetCollection();
    IQueryable<T> query = collection.AsQueryable();

    return query.OrderBy(this.SortPropertyName, this.IsDescending);
}


/// <summary>
/// 根據(jù)條件表達(dá)式返回可查詢(xún)的記錄源
/// </summary>
/// <param name="match">查詢(xún)條件</param>
/// <param name="orderByProperty">排序表達(dá)式</param>
/// <param name="isDescending">如果為true則為降序,否則為升序</param>
/// <returns></returns>
public virtual IQueryable<T> GetQueryable<TKey>(Expression<Func<T, bool>> match, Expression<Func<T, TKey>> orderByProperty, bool isDescending = true)
{
    IMongoCollection<T> collection = GetCollection();
    IQueryable<T> query = collection.AsQueryable();

    if (match != null)
    {
        query = query.Where(match);
    }

    if (orderByProperty != null)
    {
        query = isDescending ? query.OrderByDescending(orderByProperty) : query.OrderBy(orderByProperty);
    }
    else
    {
        query = query.OrderBy(this.SortPropertyName, isDescending);
    }
    return query;
}

以及基于FilterDefinition的條件處理舆乔,并返回IFindFluent<T,T>接口對(duì)象的代碼如下所示岳服。

/// <summary>
/// 根據(jù)條件表達(dá)式返回可查詢(xún)的記錄源
/// </summary>
/// <param name="query">查詢(xún)條件</param>
/// <param name="sortPropertyName">排序表達(dá)式</param>
/// <param name="isDescending">如果為true則為降序,否則為升序</param>
/// <returns></returns>
public virtual IFindFluent<T,T> GetQueryable(FilterDefinition<T> query, string sortPropertyName, bool isDescending = true)
{
    IMongoCollection<T> collection = GetCollection();
    IFindFluent<T, T> queryable = collection.Find(query);

    var sort = this.IsDescending ? Builders<T>.Sort.Descending(this.SortPropertyName) : Builders<T>.Sort.Ascending(this.SortPropertyName);
    return queryable.Sort(sort);
}

4希俩、集合的查詢(xún)操作封裝處理

基于上面的封裝吊宋,對(duì)結(jié)合的查詢(xún),也是基于不同的條件進(jìn)行處理颜武,返回對(duì)應(yīng)的列表的處理方式贫母, 最簡(jiǎn)單的是利用GetQueryable方式進(jìn)行處理,代碼如下所示盒刚。

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

或者如下所示

/// <summary>
/// 根據(jù)條件查詢(xún)數(shù)據(jù)庫(kù),并返回對(duì)象集合
/// </summary>
/// <param name="match">條件表達(dá)式</param>
/// <returns>指定對(duì)象的集合</returns>
public virtual IList<T> Find(FilterDefinition<T> query)
{
    return GetQueryable(query).ToList();
}

以及對(duì)排序字段,以及升降序的處理操作如下所示绿贞。

/// <summary>
/// 根據(jù)條件查詢(xún)數(shù)據(jù)庫(kù),并返回對(duì)象集合
/// </summary>
/// <param name="match">條件表達(dá)式</param>
/// <param name="orderByProperty">排序表達(dá)式</param>
/// <param name="isDescending">如果為true則為降序因块,否則為升序</param>
/// <returns></returns>
public virtual IList<T> Find<TKey>(Expression<Func<T, bool>> match, Expression<Func<T, TKey>> orderByProperty, bool isDescending = true)
{
    return GetQueryable<TKey>(match, orderByProperty, isDescending).ToList();
}

/// <summary>
/// 根據(jù)條件查詢(xún)數(shù)據(jù)庫(kù),并返回對(duì)象集合
/// </summary>
/// <param name="query">條件表達(dá)式</param>
/// <param name="orderByProperty">排序字段</param>
/// <param name="isDescending">如果為true則為降序,否則為升序</param>
/// <returns></returns>
public virtual IList<T> Find<TKey>(FilterDefinition<T> query, string orderByProperty, bool isDescending = true)
{
    return GetQueryable(query, orderByProperty, isDescending).ToList();
}

以及利用這些條件進(jìn)行分頁(yè)的處理代碼如下所示籍铁。

/// <summary>
/// 根據(jù)條件查詢(xún)數(shù)據(jù)庫(kù),并返回對(duì)象集合(用于分頁(yè)數(shù)據(jù)顯示)
/// </summary>
/// <param name="match">條件表達(dá)式</param>
/// <param name="info">分頁(yè)實(shí)體</param>
/// <returns>指定對(duì)象的集合</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ù)條件查詢(xún)數(shù)據(jù)庫(kù),并返回對(duì)象集合(用于分頁(yè)數(shù)據(jù)顯示)
/// </summary>
/// <param name="query">條件表達(dá)式</param>
/// <param name="info">分頁(yè)實(shí)體</param>
/// <returns>指定對(duì)象的集合</returns>
public virtual IList<T> FindWithPager(FilterDefinition<T> query, PagerInfo info)
{
    int pageindex = (info.CurrenetPageIndex < 1) ? 1 : info.CurrenetPageIndex;
    int pageSize = (info.PageSize <= 0) ? 20 : info.PageSize;

    int excludedRows = (pageindex - 1) * pageSize;

    var find = GetQueryable(query);
    info.RecordCount = (int)find.Count();

    return find.Skip(excludedRows).Limit(pageSize).ToList();
}

對(duì)于異步的封裝處理涡上,基本上也和上面的操作差不多趾断,例如對(duì)于基礎(chǔ)的查詢(xún),異步操作封裝如下所示吩愧。

/// <summary>
/// 根據(jù)條件查詢(xún)數(shù)據(jù)庫(kù),并返回對(duì)象集合
/// </summary>
/// <param name="match">條件表達(dá)式</param>
/// <returns>指定對(duì)象的集合</returns>
public virtual async Task<IList<T>> FindAsync(Expression<Func<T, bool>> match)
{
    return await Task.FromResult(GetQueryable(match).ToList());
}

/// <summary>
/// 根據(jù)條件查詢(xún)數(shù)據(jù)庫(kù),并返回對(duì)象集合
/// </summary>
/// <param name="query">條件表達(dá)式</param>
/// <returns>指定對(duì)象的集合</returns>
public virtual async Task<IList<T>> FindAsync(FilterDefinition<T> query)
{
    return await GetQueryable(query).ToListAsync();
}

復(fù)雜一點(diǎn)的分頁(yè)處理操作代碼封裝如下所示芋酌。

/// <summary>
/// 根據(jù)條件查詢(xún)數(shù)據(jù)庫(kù),并返回對(duì)象集合(用于分頁(yè)數(shù)據(jù)顯示)
/// </summary>
/// <param name="match">條件表達(dá)式</param>
/// <param name="info">分頁(yè)實(shí)體</param>
/// <returns>指定對(duì)象的集合</returns>
public virtual async Task<IList<T>> FindWithPagerAsync(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();

    var result = query.Skip(excludedRows).Take(pageSize).ToList();
    return await Task.FromResult(result);
}

/// <summary>
/// 根據(jù)條件查詢(xún)數(shù)據(jù)庫(kù),并返回對(duì)象集合(用于分頁(yè)數(shù)據(jù)顯示)
/// </summary>
/// <param name="query">條件表達(dá)式</param>
/// <param name="info">分頁(yè)實(shí)體</param>
/// <returns>指定對(duì)象的集合</returns>
public virtual async Task<IList<T>> FindWithPagerAsync(FilterDefinition<T> query, PagerInfo info)
{
    int pageindex = (info.CurrenetPageIndex < 1) ? 1 : info.CurrenetPageIndex;
    int pageSize = (info.PageSize <= 0) ? 20 : info.PageSize;

    int excludedRows = (pageindex - 1) * pageSize;

    var queryable = GetQueryable(query);
    info.RecordCount = (int)queryable.Count();

    return await queryable.Skip(excludedRows).Limit(pageSize).ToListAsync();
}

5、增刪改方法封裝處理

對(duì)于常規(guī)的增刪改操作雁佳,在新的MongoDB數(shù)據(jù)庫(kù)驅(qū)動(dòng)里面也修改了名稱(chēng)脐帝,使用的時(shí)候也需要進(jìn)行調(diào)整處理了。

/// <summary>
/// 插入指定對(duì)象到數(shù)據(jù)庫(kù)中
/// </summary>
/// <param name="t">指定的對(duì)象</param>
public virtual void Insert(T t)
{
    ArgumentValidation.CheckForNullReference(t, "傳入的對(duì)象t為空");

    IMongoCollection<T> collection = GetCollection();
    collection.InsertOne(t);
}

異步的操作實(shí)現(xiàn)如下所示糖权。

/// <summary>
/// 插入指定對(duì)象到數(shù)據(jù)庫(kù)中
/// </summary>
/// <param name="t">指定的對(duì)象</param>
public virtual async Task InsertAsync(T t)
{
    ArgumentValidation.CheckForNullReference(t, "傳入的對(duì)象t為空");

    IMongoCollection<T> collection = GetCollection();
    await collection.InsertOneAsync(t);
}

批量插入記錄的操作如下所示堵腹。

/// <summary>
/// 插入指定對(duì)象集合到數(shù)據(jù)庫(kù)中
/// </summary>
/// <param name="list">指定的對(duì)象集合</param>
public virtual void InsertBatch(IEnumerable<T> list)
{
    ArgumentValidation.CheckForNullReference(list, "傳入的對(duì)象list為空");

    IMongoCollection<T> collection = GetCollection();
    collection.InsertMany(list);
}

對(duì)應(yīng)的異步操作處理如下所示,這些都是利用原生支持的異步處理接口實(shí)現(xiàn)的星澳。

/// <summary>
/// 插入指定對(duì)象集合到數(shù)據(jù)庫(kù)中
/// </summary>
/// <param name="list">指定的對(duì)象集合</param>
public virtual async Task InsertBatchAsync(IEnumerable<T> list)
{
    ArgumentValidation.CheckForNullReference(list, "傳入的對(duì)象list為空");

    IMongoCollection<T> collection = GetCollection();
    await collection.InsertManyAsync(list);
}

更新操作疚顷,有一種整個(gè)替換更新,還有一個(gè)是部分更新禁偎,它們兩者是有區(qū)別的腿堤,如對(duì)于替換更新的操作,它的接口封裝處理如下所示

/// <summary>
/// 更新對(duì)象屬性到數(shù)據(jù)庫(kù)中
/// </summary>
/// <param name="t">指定的對(duì)象</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, "傳入的對(duì)象t為空");
    ArgumentValidation.CheckForEmptyString(id, "傳入的對(duì)象id為空");

    bool result = false;
    IMongoCollection<T> collection = GetCollection();
    //使用 IsUpsert = true 笆檀,如果沒(méi)有記錄則寫(xiě)入
    var update = collection.ReplaceOne(s => s.Id == id, t, new UpdateOptions() { IsUpsert = true });
    result = update != null && update.ModifiedCount > 0;

    return result;
}

如果對(duì)于部分字段的更新,那么操作如下所示 装处,主要是利用UpdateDefinition對(duì)象來(lái)指定需要更新那些字段屬性及值等信息误债。

/// <summary>
/// 封裝處理更新的操作(部分字段更新)
/// </summary>
/// <param name="id">主鍵的值</param>
/// <param name="update">更新對(duì)象</param>
/// <returns>執(zhí)行成功返回<c>true</c>,否則為<c>false</c></returns>
public virtual bool Update(string id, UpdateDefinition<T> update)
{
    ArgumentValidation.CheckForNullReference(update, "傳入的對(duì)象update為空");
    ArgumentValidation.CheckForEmptyString(id, "傳入的對(duì)象id為空");

    IMongoCollection<T> collection = GetCollection();
    var result = collection.UpdateOne(s => s.Id == id, update, new UpdateOptions() { IsUpsert = true });
    return result != null && result.ModifiedCount > 0;
}

上面的異步更新操作如下所示妄迁。

/// <summary>
/// 封裝處理更新的操作(部分字段更新)
/// </summary>
/// <param name="id">主鍵的值</param>
/// <param name="update">更新對(duì)象</param>
/// <returns>執(zhí)行成功返回<c>true</c>寝蹈,否則為<c>false</c></returns>
public virtual async Task<bool> UpdateAsync(string id, UpdateDefinition<T> update)
{
    ArgumentValidation.CheckForNullReference(update, "傳入的對(duì)象update為空");
    ArgumentValidation.CheckForEmptyString(id, "傳入的對(duì)象id為空");

    IMongoCollection<T> collection = GetCollection();
    var result = await collection.UpdateOneAsync(s => s.Id == id, update, new UpdateOptions() { IsUpsert = true });

    var sucess = result != null && result.ModifiedCount > 0;
    return await Task.FromResult(sucess);
}

刪除的操作也是類(lèi)似的了,基本上和上面的處理方式接近登淘,順便列出來(lái)供參考學(xué)習(xí)箫老。

/// <summary>
/// 根據(jù)指定對(duì)象的ID,從數(shù)據(jù)庫(kù)中刪除指定對(duì)象
/// </summary>
/// <param name="id">對(duì)象的ID</param>
/// <returns>執(zhí)行成功返回<c>true</c>,否則為<c>false</c>黔州。</returns>
public virtual bool Delete(string id)
{
    ArgumentValidation.CheckForEmptyString(id, "傳入的對(duì)象id為空");

    IMongoCollection<T> collection = GetCollection();
    var result = collection.DeleteOne(s=> s.Id == id);
    return result != null && result.DeletedCount > 0;
}

/// <summary>
/// 根據(jù)指定對(duì)象的ID,從數(shù)據(jù)庫(kù)中刪除指定指定的對(duì)象
/// </summary>
/// <param name="idList">對(duì)象的ID集合</param>
/// <returns>執(zhí)行成功返回<c>true</c>耍鬓,否則為<c>false</c>。</returns>
public virtual bool DeleteBatch(List<string> idList)
{
    ArgumentValidation.CheckForNullReference(idList, "傳入的對(duì)象idList為空");

    IMongoCollection<T> collection = GetCollection();
    var query = Query.In("_id", new BsonArray(idList));
    var result = collection.DeleteMany(s => idList.Contains(s.Id));
    return result != null && result.DeletedCount > 0;
}

如果根據(jù)條件的刪除流妻,也可以利用條件定義的兩種方式牲蜀,具體代碼如下所示。

/// <summary>
/// 根據(jù)指定條件,從數(shù)據(jù)庫(kù)中刪除指定對(duì)象
/// </summary>
/// <param name="match">條件表達(dá)式</param>
/// <returns>執(zhí)行成功返回<c>true</c>绅这,否則為<c>false</c>涣达。</returns>
public virtual bool DeleteByExpression(Expression<Func<T, bool>> match)
{
    IMongoCollection<T> collection = GetCollection();
    collection.AsQueryable().Where(match).ToList().ForEach(s => collection.DeleteOne(t => t.Id == s.Id));
    return true;
}

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

6度苔、數(shù)據(jù)訪問(wèn)子類(lèi)的封裝和方法調(diào)用

好了匆篓,基本上上面大多數(shù)使用的方法都發(fā)布出來(lái)了,封裝的原則就是希望數(shù)據(jù)訪問(wèn)層子類(lèi)能夠簡(jiǎn)化代碼寇窑,減少不必要的復(fù)制粘貼鸦概,而且必要的時(shí)候, 也可以對(duì)具體的接口進(jìn)行重寫(xiě)甩骏,實(shí)現(xiàn)更強(qiáng)大的處理控制窗市。

例如對(duì)于上面的基類(lèi),我們?cè)诰唧w的集合對(duì)象封裝的時(shí)候横漏,需要繼承于BaseDAL<T>這樣的方式谨设,這樣可以利用基類(lèi)豐富的接口,簡(jiǎn)化子類(lèi)的代碼缎浇,如User集合類(lèi)的代碼如下所示扎拣。

/// <summary>
/// User集合(表)的數(shù)據(jù)訪問(wèn)類(lèi)
/// </summary>
public class User : BaseDAL<UserInfo>
{
    /// <summary>
    /// 默認(rèn)構(gòu)造函數(shù)
    /// </summary>
    public User() 
    {
        this.entitysName = "users";//對(duì)象在數(shù)據(jù)庫(kù)的集合名稱(chēng)
    }

    /// <summary>
    /// 為用戶(hù)增加歲數(shù)
    /// </summary>
    /// <param name="id">記錄ID</param>
    /// <param name="addAge">待增加的歲數(shù)</param>
    /// <returns></returns>
    public bool IncreaseAge(string id, int addAge)
    {
        var collection = GetCollection();
        var update = Builders<UserInfo>.Update.Inc(s => s.Age, addAge);
        var result = collection.UpdateOne(s => s.Id == id, update);
        return result != null && result.ModifiedCount > 0;
    }

    /// <summary>
    /// 單獨(dú)修改用戶(hù)的名稱(chēng)
    /// </summary>
    /// <param name="id">記錄ID</param>
    /// <param name="newName">用戶(hù)新名稱(chēng)</param>
    /// <returns></returns>
    public bool UpdateName(string id, string newName)
    {
        var collection = GetCollection();
        var update = Builders<UserInfo>.Update.Set(s => s.Name, newName);
        var result = collection.UpdateOne(s => s.Id == id, update);
        return result != null && result.ModifiedCount > 0;
    }
}

在界面層使用的時(shí)候,只需要聲明一個(gè)對(duì)應(yīng)的User數(shù)據(jù)訪問(wèn)類(lèi)dal對(duì)象素跺,就可以利用它的相關(guān)接口進(jìn)行對(duì)應(yīng)的數(shù)據(jù)操作了二蓝,如下代碼所示。

IList<UserInfo> members = dal.Find(s => s.Name.StartsWith("Test"));
foreach (UserInfo info in members)
{
    Console.WriteLine(info.Id + ", " + info.Name);
}
var user = dal.FindSingle(s => s.Id == "56815e6634ab091e1406ec68");
if(user != null)
{
    Console.WriteLine(user.Name);
}

對(duì)于部分字段的更新處理指厌,在界面上刊愚,我們可以利用封裝好的接口進(jìn)行處理,如下所示踩验。

/// <summary>
/// 測(cè)試部分字段修改的處理
/// </summary>
private void btnAddAge_Click(object sender, EventArgs e)
{
    UserInfo info = dal.GetAll()[0];
    if(info != null)
    {
        Console.WriteLine("Age before Incr:" + info.Age);

        int addAge = 10;
        dal.IncreaseAge(info.Id, addAge);

        info = dal.FindByID(info.Id);
        Console.WriteLine("Age after Incr:" + info.Age);


        Console.WriteLine("Name before modify:" + info.Name);
        var update = Builders<UserInfo>.Update.Set(s => s.Name, info.Name + DateTime.Now.Second);
        dal.Update(info.Id, update);

        info = dal.FindByID(info.Id);
        Console.WriteLine("Name after modify:" + info.Name);
    }
}

對(duì)于異步接口的調(diào)用代碼鸥诽,如下所示。

/// <summary>
/// 異步操作的調(diào)用
/// </summary>
private async void btnAsync_Click(object sender, EventArgs e)
{
    UserInfo newInfo = new UserInfo();
    newInfo.Name = "Ping" + DateTime.Now.ToString();
    newInfo.Age = DateTime.Now.Minute;
    newInfo.Hobby = "乒乓球";
    await dal.InsertAsync(newInfo);

    var list = await dal.FindAsync(s => s.Age < 30);
    foreach (UserInfo info in list)
    {
        Console.WriteLine(info.Id + ", " + info.Name);
    }
    Console.WriteLine(newInfo.Id);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末箕憾,一起剝皮案震驚了整個(gè)濱河市牡借,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌袭异,老刑警劉巖钠龙,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異御铃,居然都是意外死亡碴里,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)上真,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)咬腋,“玉大人,你說(shuō)我怎么就攤上這事睡互〉刍穑” “怎么了溜徙?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)犀填。 經(jīng)常有香客問(wèn)我,道長(zhǎng)嗓违,這世上最難降的妖魔是什么九巡? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮蹂季,結(jié)果婚禮上冕广,老公的妹妹穿的比我還像新娘。我一直安慰自己偿洁,他們只是感情好撒汉,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著涕滋,像睡著了一般睬辐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宾肺,一...
    開(kāi)封第一講書(shū)人閱讀 52,158評(píng)論 1 308
  • 那天溯饵,我揣著相機(jī)與錄音,去河邊找鬼锨用。 笑死丰刊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的增拥。 我是一名探鬼主播啄巧,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼掌栅!你這毒婦竟也來(lái)了秩仆?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤渣玲,失蹤者是張志新(化名)和其女友劉穎逗概,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體忘衍,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡逾苫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了枚钓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铅搓。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖搀捷,靈堂內(nèi)的尸體忽然破棺而出星掰,到底是詐尸還是另有隱情多望,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布氢烘,位于F島的核電站怀偷,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏播玖。R本人自食惡果不足惜椎工,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蜀踏。 院中可真熱鬧维蒙,春花似錦、人聲如沸果覆。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)局待。三九已至斑响,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間燎猛,已是汗流浹背恋捆。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留重绷,地道東北人沸停。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像昭卓,于是被迫代替她去往敵國(guó)和親愤钾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容