日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

.net平台的MongoDB使用

發布時間:2023/11/29 编程问答 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .net平台的MongoDB使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

網址:http://www.cnblogs.com/skychen1218/p/6595759.html

前言

  最近花了點時間玩了下MongoDB.Driver,進行封裝了工具庫,平常也會經常用到MongoDB,因此寫一篇文章梳理知識同時把自己的成果分享給大家。

  本篇會設計到Lambda表達式的解析,有興趣的同學也看看我之前寫的《表達式樹的解析》。

  文章最后會給出源碼下載地址。

MongoDB簡介

  MongoDB是一個基于分布式文件存儲的非關系型數據庫,相比于其他NoSql它支持復雜的查詢。

  文本是類似JSON的BSON格式,BSON是在JSON的基礎上進化:更快的遍歷、操作更簡易、更多的數據類型。因此MongoDB可以存儲比較復雜的數據類型,同樣也支持建立索引。

  MongoDB的概念有:

  • DataBase(庫)
  • Collections(集合),類似于關系型數據庫的表
  • Document(文檔),類似于關系型數據庫的一條數據

  

MongoDB優缺點

  • 優點

  • 高效性,內置GridFS,從而達到海量數據存儲,并且滿足大數據集的快速范圍查詢。
  • 高擴展性,分片使MongoDB的有更高的吞吐量,復制使MongoDB更高的可用性。
  • BSON文檔,易于理解、查看,
  • 免費
    • 缺點

  • 不支持事務
  • 不支持表關聯
  • 不耗CPU卻耗內存
  • 沒有成熟的管理工具
  • MongoDB使用場景

      擁有高效的存儲的特點,讓MongoDB用在操作日志記錄是非常流行的做法。

      隨著版本的升級提供更加強大的功能,產品逐漸成熟用在主業務也很多,例如電商行業的訂單系統與包裹跟蹤模塊,海量的主訂單與訂單明細,包裹的狀態變更信息。

      然而因為BSON文檔的存儲方式,使平常的開發的思維模式有所變更。舉個栗子,傳統用關系型數據庫,訂單模塊就會分主訂單表和訂單明細表,創建訂單就會用事務同時添加兩表的數據,查找訂單也會通過兩表關聯查詢出來。但是使用MongoDB,主訂單表與其明細,將會以一個完整的對象保存為文檔。

      也因為不支持事務、表關聯的原因,它更加適合用作于一個完整的業務模塊。

      部分朋友會帶著一個問題,非關系型數據庫和關系型數據庫哪個更好。我認為,誰都無法代替誰,一般情況下,非關系型數據庫更多的作為關系型數據庫擴展,用好了效果甚佳,濫用了只會寸步難行。

      

    MongoDB安裝

      本來想寫的,相應的文章在園子太多了,借用一位仁兄的博文,傳送門

      MongoDB下載地址:https://www.mongodb.com/download-center#community

      管理工具:Robomongo,傳送門

    MongoDB.Driver的使用

      

      創建一個控制臺,到Nuget下載MongoDB.Driver。寫入以下代碼:

    ?

    using System;
    using FrameWork.MongoDB.MongoDbConfig;
    using MongoDB.Bson.Serialization.Attributes;
    using MongoDB.Driver;

    namespace FrameWork.MongoDb.Demo
    {
    class Program
    {
    static void Main(string[] args)
    {
    var database = "testdatabase";
    var collection = "TestMongo";
    var db = new MongoClient("您的地址").GetDatabase(database);
    var coll = db.GetCollection<TestMongo>(collection);

    var entity = new TestMongo
    {
    Name = "SkyChen",
    Amount = 100,
    CreateDateTime = DateTime.Now
    };

    coll.InsertOneAsync(entity).ConfigureAwait(false);

    }
    }

    public class TestMongo : MongoEntity
    {

    [BsonDateTimeOptions(Kind = DateTimeKind.Local)]
    public DateTime CreateDateTime { get; set; }

    public decimal Amount { get; set; }

    public string Name { get; set; }

    }
    }

      第一個demo:添加數據就完成了。F12可以看到IMongoCollection這個接口,增刪改查都有,注意分One和Many。基礎的使用就不扯過多,在文章尾部的代碼已經提供增刪改查的封裝。

      增刪查的封裝相對簡單,但是MongoDB.Driver提供的update的稍微比較特殊。通過Builders<T>.Update.Set(_fieldname, value)更新指定字段名,有多個字段名需要修改,就要通過new UpdateDefinitionBuilder<T>().Combine(updateDefinitionList)去完成

      然而,這種方式并不適用于我們實際開發,因此需要對Update方法進行?實體更新封裝Lambda更新封裝

    實體更新封裝

      通過ID作為過濾條件更新整個實體在實際工作中是常有的。既然通過ID作為條件,那么只能通過UpdateOneAsync進行約束更新一條數據。更新的字段可以通過反射實體對象進行遍歷屬性。下邊是實現代碼:

    /// <summary>
    /// mongodb擴展方法
    /// </summary>
    internal static class MongoDbExtension
    {
    /// <summary>
    /// 獲取更新信息
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entity"></param>
    /// <returns></returns>
    internal static UpdateDefinition<T> GetUpdateDefinition<T>(this T entity)
    {
    var properties = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public);

    var updateDefinitionList = GetUpdateDefinitionList<T>(properties, entity);

    var updateDefinitionBuilder = new UpdateDefinitionBuilder<T>().Combine(updateDefinitionList);

    return updateDefinitionBuilder;
    }

    /// <summary>
    /// 獲取更新信息
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="propertyInfos"></param>
    /// <param name="entity"></param>
    /// <returns></returns>
    internal static List<UpdateDefinition<T>> GetUpdateDefinitionList<T>(PropertyInfo[] propertyInfos, object entity)
    {
    var updateDefinitionList = new List<UpdateDefinition<T>>();

    propertyInfos = propertyInfos.Where(a => a.Name != "_id").ToArray();

    foreach (var propertyInfo in propertyInfos)
    {
    if (propertyInfo.PropertyType.IsArray || typeof(IList).IsAssignableFrom(propertyInfo.PropertyType))
    {
    var value = propertyInfo.GetValue(entity) as IList;

    var filedName = propertyInfo.Name;

    updateDefinitionList.Add(Builders<T>.Update.Set(filedName, value));
    }
    else
    {
    var value = propertyInfo.GetValue(entity);
    if (propertyInfo.PropertyType == typeof(decimal))
    value = value.ToString();

    var filedName = propertyInfo.Name;

    updateDefinitionList.Add(Builders<T>.Update.Set(filedName, value));
    }
    }

    return updateDefinitionList;
    }
    }

    ?

    Lambda表達式更新封裝

      曾經用過其他ORM都清楚Lambda表達式使用是非常頻繁的,MongoDB.Driver已經支持Lambda表達式的過濾條件,但沒支持部分字段更新,因此由我們自己來寫解析。下邊是現實代碼:

    ?

    #region Mongo更新字段表達式解析
    /// <summary>
    /// Mongo更新字段表達式解析
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class MongoDbExpression<T> : ExpressionVisitor
    {
    #region 成員變量
    /// <summary>
    /// 更新列表
    /// </summary>
    internal List<UpdateDefinition<T>> UpdateDefinitionList = new List<UpdateDefinition<T>>();
    private string _fieldname;

    #endregion

    #region 獲取更新列表
    /// <summary>
    /// 獲取更新列表
    /// </summary>
    /// <param name="expression"></param>
    /// <returns></returns>
    public static List<UpdateDefinition<T>> GetUpdateDefinition(Expression<Func<T, T>> expression)
    {
    var mongoDb = new MongoDbExpression<T>();

    mongoDb.Resolve(expression);
    return mongoDb.UpdateDefinitionList;
    }
    #endregion

    #region 解析表達式
    /// <summary>
    /// 解析表達式
    /// </summary>
    /// <param name="expression"></param>
    private void Resolve(Expression<Func<T, T>> expression)
    {
    Visit(expression);
    }
    #endregion

    #region 訪問對象初始化表達式

    /// <summary>
    /// 訪問對象初始化表達式
    /// </summary>
    /// <param name="node"></param>
    /// <returns></returns>
    protected override Expression VisitMemberInit(MemberInitExpression node)
    {
    var bingdings = node.Bindings;

    foreach (var item in bingdings)
    {
    var memberAssignment = (MemberAssignment)item;
    _fieldname = item.Member.Name;

    if (memberAssignment.Expression.NodeType == ExpressionType.MemberInit)
    {
    var lambda = Expression.Lambda<Func<object>>(Expression.Convert(memberAssignment.Expression, typeof(object)));
    var value = lambda.Compile().Invoke();
    UpdateDefinitionList.Add(Builders<T>.Update.Set(_fieldname, value));
    }
    else
    {
    Visit(memberAssignment.Expression);
    }
    }
    return node;
    }

    #endregion

    #region 訪問二元表達式

    /// <summary>
    /// 訪問二元表達式
    /// </summary>
    /// <param name="node"></param>
    /// <returns></returns>
    protected override Expression VisitBinary(BinaryExpression node)
    {
    UpdateDefinition<T> updateDefinition;

    var value = ((ConstantExpression)node.Right).Value;
    if (node.Type == typeof(int))
    {
    var realValue = (int)value;
    if (node.NodeType == ExpressionType.Decrement)
    realValue = -realValue;

    updateDefinition = Builders<T>.Update.Inc(_fieldname, realValue);
    }
    else if (node.Type == typeof(long))
    {
    var realValue = (long)value;
    if (node.NodeType == ExpressionType.Decrement)
    realValue = -realValue;

    updateDefinition = Builders<T>.Update.Inc(_fieldname, realValue);
    }
    else if (node.Type == typeof(double))
    {
    var realValue = (double)value;
    if (node.NodeType == ExpressionType.Decrement)
    realValue = -realValue;

    updateDefinition = Builders<T>.Update.Inc(_fieldname, realValue);
    }
    else if (node.Type == typeof(decimal))
    {
    var realValue = (decimal)value;
    if (node.NodeType == ExpressionType.Decrement)
    realValue = -realValue;

    updateDefinition = Builders<T>.Update.Inc(_fieldname, realValue);
    }
    else if (node.Type == typeof(float))
    {
    var realValue = (float)value;
    if (node.NodeType == ExpressionType.Decrement)
    realValue = -realValue;

    updateDefinition = Builders<T>.Update.Inc(_fieldname, realValue);
    }
    else
    {
    throw new Exception(_fieldname + "不支持該類型操作");
    }

    UpdateDefinitionList.Add(updateDefinition);

    return node;
    }
    #endregion

    #region 訪問數組表達式

    /// <summary>
    /// 訪問數組表達式
    /// </summary>
    /// <param name="node"></param>
    /// <returns></returns>
    protected override Expression VisitNewArray(NewArrayExpression node)
    {
    var listLambda = Expression.Lambda<Func<IList>>(node);
    var list = listLambda.Compile().Invoke();
    UpdateDefinitionList.Add(Builders<T>.Update.Set(_fieldname, list));

    return node;
    }

    /// <summary>
    /// 訪問集合表達式
    /// </summary>
    /// <param name="node"></param>
    /// <returns></returns>
    protected override Expression VisitListInit(ListInitExpression node)
    {
    var listLambda = Expression.Lambda<Func<IList>>(node);
    var list = listLambda.Compile().Invoke();
    UpdateDefinitionList.Add(Builders<T>.Update.Set(_fieldname, list));

    return node;
    }
    #endregion

    #region 訪問常量表達式

    /// <summary>
    /// 訪問常量表達式
    /// </summary>
    /// <param name="node"></param>
    /// <returns></returns>
    protected override Expression VisitConstant(ConstantExpression node)
    {
    var value = node.Type.IsEnum ? (int)node.Value : node.Value;

    UpdateDefinitionList.Add(Builders<T>.Update.Set(_fieldname, value));

    return node;
    }
    #endregion

    #region 訪問成員表達式

    /// <summary>
    /// 訪問成員表達式
    /// </summary>
    /// <param name="node"></param>
    /// <returns></returns>
    protected override Expression VisitMember(MemberExpression node)
    {
    if (node.Type.GetInterfaces().Any(a => a.Name == "IList"))
    {
    var lambda = Expression.Lambda<Func<IList>>(node);
    var value = lambda.Compile().Invoke();

    UpdateDefinitionList.Add(Builders<T>.Update.Set(_fieldname, value));
    }
    else
    {
    var lambda = Expression.Lambda<Func<object>>(Expression.Convert(node, typeof(object)));
    var value = lambda.Compile().Invoke();

    if (node.Type.IsEnum)
    value = (int)value;

    UpdateDefinitionList.Add(Builders<T>.Update.Set(_fieldname, value));
    }

    return node;
    }
    #endregion
    }
    #endregion

    ?

    表達式樹的解析

      對于Lambda表達式的封裝,我側重講一下。假如有一段這樣的更新代碼:  

    new MongoDbService().Update<User>(a => a._id == "d99ce40d7a0b49768b74735b91f2aa75", a => new User{AddressList = new List<string>{"number1","number2"},Age = 10,BirthDateTime = DateTime.Now,Name = "skychen",NumList = new List<int>{1211,23344},Sex = Sex.Woman,Son = new User{Name = "xiaochenpi",Age = 1}});

      那么,我們可以調試監視看看(下圖),我們可以得出兩個重要信息:

      1.Expression<Func<T, T>>解析出來Body的NodeType是MemberInit

      2.Bindings里有需要修改的字段信息。

      再調試進去看看Bindings的第一項,我們又可以了解了幾個重要信息。

      1.Bindings里的元素是MemberAssignment類型。

      2.Member能取到Name屬性,也就是字段名

      3.Expression屬性,使用 Expression.Lambda,進行Compile().Invoke()就能得到我們需要的值。

      fileName和Value都能取到了,那么更新自然能解決了。

      上圖是源碼的部分核心代碼,奇怪的是,我并沒有在VisitMemberInit里進行遍歷Bindings后進行Update.Set,而是將item的Expression屬性再一次訪問。那是因為我需要針對不同的數據類型進行處理。例如:

      常量,我可以定義一個object value進行去接收,如果遇到枚舉我需要強轉成整型。

      集合與數組,假如草率的使用object類型,object value =?Expression.Lambda<Func<object>>(node).Compile().Invoke(),那么更新到MongoDB里就會有bug,奇怪的_t,_v就會出現。以此我需要定義為IList才能解決這個問題。

      此外,工作中還會遇到金額或者數量自增的情況。Amount = a.Amount+9.9M,Count =a.Count-1。?MongoDB.Driver提供了Builders<T>.Update.Inc方法,因此重寫二元表達式進行封裝。

    附加

      經過測試,官方驅動2.4.3和2.4.4版本對類型IList支持有問題,如下圖,所以現在封裝版本最高支持到2.4.2。

      

    結束

      不知道有多少朋友直接拖到文章尾部直接下載源碼的。。。。。。

      如果對您有用,麻煩您推薦一下。

      此外還要感謝非非大哥哥,率先做了我的小白鼠給我提出了可貴的BUG,不然我還真不敢放出源碼。

      如果有什么問題和建議,可以在下方評論,我會及時回復。

      雙手奉上源碼:https://github.com/SkyChenSky/Framework.MongoDB.git

    轉載于:https://www.cnblogs.com/zxtceq/p/7692189.html

    總結

    以上是生活随笔為你收集整理的.net平台的MongoDB使用的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。