近期工作中有使用到 MongoDb作为日志持久化对象,需要实现对MongoDb的增、删、改、查,但由于MongoDb的版本比较新,是2.4以上版本的,网上已有的一些MongoDb Helper类都是基于之前MongoDb旧的版本,无法适用于新版本的MongoDb,故我基于MongoDb官方C#驱动重新封装了MongoDbCsharpHelper类(CRUD类),完整代码如下:

  1. using MongoDB;
  2. using MongoDB.Bson;
  3. using MongoDB.Driver;
  4. using System;
  5. using System.Collections;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Linq.Expressions;
  9. using System.Reflection;
  10. using System.Threading;
  11. using System.Web;
  12.  
  13. namespace Zuowj.Utils
  14. {
  15. /// <summary>
  16. /// MongoDbCsharpHelper:MongoDb基于C#语言操作帮助类
  17. /// Author:Zuowenjun
  18. /// Date:2017/11/16
  19. /// </summary>
  20. public class MongoDbCsharpHelper
  21. {
  22. private readonly string connectionString = null;
  23. private readonly string databaseName = null;
  24. private MongoDB.Driver.IMongoDatabase database = null;
  25. private readonly bool autoCreateDb = false;
  26. private readonly bool autoCreateCollection = false;
  27.  
  28. static MongoDbCsharpHelper()
  29. {
  30. BsonDefaults.GuidRepresentation = GuidRepresentation.Standard;
  31. }
  32.  
  33. public MongoDbCsharpHelper(string mongoConnStr, string dbName, bool autoCreateDb = false, bool autoCreateCollection = false)
  34. {
  35. this.connectionString = mongoConnStr;
  36. this.databaseName = dbName;
  37. this.autoCreateDb = autoCreateDb;
  38. this.autoCreateCollection = autoCreateCollection;
  39. }
  40.  
  41. #region 私有方法
  42.  
  43. private MongoClient CreateMongoClient()
  44. {
  45. return new MongoClient(connectionString);
  46. }
  47.  
  48. private MongoDB.Driver.IMongoDatabase GetMongoDatabase()
  49. {
  50. if (database == null)
  51. {
  52. var client = CreateMongoClient();
  53. if (!DatabaseExists(client, databaseName) && !autoCreateDb)
  54. {
  55. throw new KeyNotFoundException("此MongoDB名称不存在:" + databaseName);
  56. }
  57.  
  58. database = CreateMongoClient().GetDatabase(databaseName);
  59. }
  60.  
  61. return database;
  62. }
  63.  
  64. private bool DatabaseExists(MongoClient client, string dbName)
  65. {
  66. try
  67. {
  68. var dbNames = client.ListDatabases().ToList().Select(db => db.GetValue("name").AsString);
  69. return dbNames.Contains(dbName);
  70. }
  71. catch //如果连接的账号不能枚举出所有DB会报错,则默认为true
  72. {
  73. return true;
  74. }
  75.  
  76. }
  77.  
  78. private bool CollectionExists(IMongoDatabase database, string collectionName)
  79. {
  80. var options = new ListCollectionsOptions
  81. {
  82. Filter = Builders<BsonDocument>.Filter.Eq("name", collectionName)
  83. };
  84.  
  85. return database.ListCollections(options).ToEnumerable().Any();
  86. }
  87.  
  88. private MongoDB.Driver.IMongoCollection<TDoc> GetMongoCollection<TDoc>(string name, MongoCollectionSettings settings = null)
  89. {
  90. var mongoDatabase = GetMongoDatabase();
  91.  
  92. if (!CollectionExists(mongoDatabase, name) && !autoCreateCollection)
  93. {
  94. throw new KeyNotFoundException("此Collection名称不存在:" + name);
  95. }
  96.  
  97. return mongoDatabase.GetCollection<TDoc>(name, settings);
  98. }
  99.  
  100. private List<UpdateDefinition<TDoc>> BuildUpdateDefinition<TDoc>(object doc, string parent)
  101. {
  102. var updateList = new List<UpdateDefinition<TDoc>>();
  103. foreach (var property in typeof(TDoc).GetProperties(BindingFlags.Instance | BindingFlags.Public))
  104. {
  105. var key = parent == null ? property.Name : string.Format("{0}.{1}", parent, property.Name);
  106. //非空的复杂类型
  107. if ((property.PropertyType.IsClass || property.PropertyType.IsInterface) && property.PropertyType != typeof(string) && property.GetValue(doc) != null)
  108. {
  109. if (typeof(IList).IsAssignableFrom(property.PropertyType))
  110. {
  111. #region 集合类型
  112. int i = 0;
  113. var subObj = property.GetValue(doc);
  114. foreach (var item in subObj as IList)
  115. {
  116. if (item.GetType().IsClass || item.GetType().IsInterface)
  117. {
  118. updateList.AddRange(BuildUpdateDefinition<TDoc>(doc, string.Format("{0}.{1}", key, i)));
  119. }
  120. else
  121. {
  122. updateList.Add(Builders<TDoc>.Update.Set(string.Format("{0}.{1}", key, i), item));
  123. }
  124. i++;
  125. }
  126. #endregion
  127. }
  128. else
  129. {
  130. #region 实体类型
  131. //复杂类型,导航属性,类对象和集合对象
  132. var subObj = property.GetValue(doc);
  133. foreach (var sub in property.PropertyType.GetProperties(BindingFlags.Instance | BindingFlags.Public))
  134. {
  135. updateList.Add(Builders<TDoc>.Update.Set(string.Format("{0}.{1}", key, sub.Name), sub.GetValue(subObj)));
  136. }
  137. #endregion
  138. }
  139. }
  140. else //简单类型
  141. {
  142. updateList.Add(Builders<TDoc>.Update.Set(key, property.GetValue(doc)));
  143. }
  144. }
  145.  
  146. return updateList;
  147. }
  148.  
  149. private void CreateIndex<TDoc>(IMongoCollection<TDoc> col, string[] indexFields, CreateIndexOptions options = null)
  150. {
  151. if (indexFields == null)
  152. {
  153. return;
  154. }
  155. var indexKeys = Builders<TDoc>.IndexKeys;
  156. IndexKeysDefinition<TDoc> keys = null;
  157. if (indexFields.Length > 0)
  158. {
  159. keys = indexKeys.Descending(indexFields[0]);
  160. }
  161. for (var i = 1; i < indexFields.Length; i++)
  162. {
  163. var strIndex = indexFields[i];
  164. keys = keys.Descending(strIndex);
  165. }
  166.  
  167. if (keys != null)
  168. {
  169. col.Indexes.CreateOne(keys, options);
  170. }
  171.  
  172. }
  173.  
  174. #endregion
  175.  
  176. public void CreateCollectionIndex<TDoc>(string collectionName, string[] indexFields, CreateIndexOptions options = null)
  177. {
  178. CreateIndex(GetMongoCollection<TDoc>(collectionName), indexFields, options);
  179. }
  180.  
  181. public void CreateCollection<TDoc>(string[] indexFields = null, CreateIndexOptions options = null)
  182. {
  183. string collectionName = typeof(TDoc).Name;
  184. CreateCollection<TDoc>(collectionName, indexFields, options);
  185. }
  186.  
  187. public void CreateCollection<TDoc>(string collectionName, string[] indexFields = null, CreateIndexOptions options = null)
  188. {
  189. var mongoDatabase = GetMongoDatabase();
  190. mongoDatabase.CreateCollection(collectionName);
  191. CreateIndex(GetMongoCollection<TDoc>(collectionName), indexFields, options);
  192. }
  193.  
  194. public List<TDoc> Find<TDoc>(Expression<Func<TDoc, bool>> filter, FindOptions options = null)
  195. {
  196. string collectionName = typeof(TDoc).Name;
  197. return Find<TDoc>(collectionName, filter, options);
  198. }
  199.  
  200. public List<TDoc> Find<TDoc>(string collectionName, Expression<Func<TDoc, bool>> filter, FindOptions options = null)
  201. {
  202. var colleciton = GetMongoCollection<TDoc>(collectionName);
  203. return colleciton.Find(filter, options).ToList();
  204. }
  205.  
  206. public List<TDoc> FindByPage<TDoc, TResult>(Expression<Func<TDoc, bool>> filter, Expression<Func<TDoc, TResult>> keySelector, int pageIndex, int pageSize, out int rsCount)
  207. {
  208. string collectionName = typeof(TDoc).Name;
  209. return FindByPage<TDoc, TResult>(collectionName, filter, keySelector, pageIndex, pageSize, out rsCount);
  210. }
  211.  
  212. public List<TDoc> FindByPage<TDoc, TResult>(string collectionName, Expression<Func<TDoc, bool>> filter, Expression<Func<TDoc, TResult>> keySelector, int pageIndex, int pageSize, out int rsCount)
  213. {
  214. var colleciton = GetMongoCollection<TDoc>(collectionName);
  215. rsCount = colleciton.AsQueryable().Where(filter).Count();
  216.  
  217. int pageCount = rsCount / pageSize + ((rsCount % pageSize) > 0 ? 1 : 0);
  218. if (pageIndex > pageCount) pageIndex = pageCount;
  219. if (pageIndex <= 0) pageIndex = 1;
  220.  
  221. return colleciton.AsQueryable(new AggregateOptions { AllowDiskUse = true }).Where(filter).OrderByDescending(keySelector).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
  222. }
  223.  
  224. public void Insert<TDoc>(TDoc doc, InsertOneOptions options = null)
  225. {
  226. string collectionName = typeof(TDoc).Name;
  227. Insert<TDoc>(collectionName, doc, options);
  228. }
  229.  
  230. public void Insert<TDoc>(string collectionName, TDoc doc, InsertOneOptions options = null)
  231. {
  232. var colleciton = GetMongoCollection<TDoc>(collectionName);
  233. colleciton.InsertOne(doc, options);
  234. }
  235.  
  236. public void InsertMany<TDoc>(IEnumerable<TDoc> docs, InsertManyOptions options = null)
  237. {
  238. string collectionName = typeof(TDoc).Name;
  239. InsertMany<TDoc>(collectionName, docs, options);
  240. }
  241.  
  242. public void InsertMany<TDoc>(string collectionName, IEnumerable<TDoc> docs, InsertManyOptions options = null)
  243. {
  244. var colleciton = GetMongoCollection<TDoc>(collectionName);
  245. colleciton.InsertMany(docs, options);
  246. }
  247.  
  248. public void Update<TDoc>(TDoc doc, Expression<Func<TDoc, bool>> filter, UpdateOptions options = null)
  249. {
  250. string collectionName = typeof(TDoc).Name;
  251. var colleciton = GetMongoCollection<TDoc>(collectionName);
  252. List<UpdateDefinition<TDoc>> updateList = BuildUpdateDefinition<TDoc>(doc, null);
  253. colleciton.UpdateOne(filter, Builders<TDoc>.Update.Combine(updateList), options);
  254. }
  255.  
  256. public void Update<TDoc>(string collectionName, TDoc doc, Expression<Func<TDoc, bool>> filter, UpdateOptions options = null)
  257. {
  258. var colleciton = GetMongoCollection<TDoc>(collectionName);
  259. List<UpdateDefinition<TDoc>> updateList = BuildUpdateDefinition<TDoc>(doc, null);
  260. colleciton.UpdateOne(filter, Builders<TDoc>.Update.Combine(updateList), options);
  261. }
  262.  
  263. public void Update<TDoc>(TDoc doc, Expression<Func<TDoc, bool>> filter, UpdateDefinition<TDoc> updateFields, UpdateOptions options = null)
  264. {
  265. string collectionName = typeof(TDoc).Name;
  266. Update<TDoc>(collectionName, doc, filter, updateFields, options);
  267. }
  268.  
  269. public void Update<TDoc>(string collectionName, TDoc doc, Expression<Func<TDoc, bool>> filter, UpdateDefinition<TDoc> updateFields, UpdateOptions options = null)
  270. {
  271. var colleciton = GetMongoCollection<TDoc>(collectionName);
  272. colleciton.UpdateOne(filter, updateFields, options);
  273. }
  274.  
  275. public void UpdateMany<TDoc>(TDoc doc, Expression<Func<TDoc, bool>> filter, UpdateOptions options = null)
  276. {
  277. string collectionName = typeof(TDoc).Name;
  278. UpdateMany<TDoc>(collectionName, doc, filter, options);
  279. }
  280.  
  281. public void UpdateMany<TDoc>(string collectionName, TDoc doc, Expression<Func<TDoc, bool>> filter, UpdateOptions options = null)
  282. {
  283. var colleciton = GetMongoCollection<TDoc>(collectionName);
  284. List<UpdateDefinition<TDoc>> updateList = BuildUpdateDefinition<TDoc>(doc, null);
  285. colleciton.UpdateMany(filter, Builders<TDoc>.Update.Combine(updateList), options);
  286. }
  287.  
  288. public void Delete<TDoc>(Expression<Func<TDoc, bool>> filter, DeleteOptions options = null)
  289. {
  290. string collectionName = typeof(TDoc).Name;
  291. Delete<TDoc>(collectionName, filter, options);
  292. }
  293.  
  294. public void Delete<TDoc>(string collectionName, Expression<Func<TDoc, bool>> filter, DeleteOptions options = null)
  295. {
  296. var colleciton = GetMongoCollection<TDoc>(collectionName);
  297. colleciton.DeleteOne(filter, options);
  298. }
  299.  
  300. public void DeleteMany<TDoc>(Expression<Func<TDoc, bool>> filter, DeleteOptions options = null)
  301. {
  302. string collectionName = typeof(TDoc).Name;
  303. DeleteMany<TDoc>(collectionName, filter, options);
  304. }
  305.  
  306. public void DeleteMany<TDoc>(string collectionName, Expression<Func<TDoc, bool>> filter, DeleteOptions options = null)
  307. {
  308. var colleciton = GetMongoCollection<TDoc>(collectionName);
  309. colleciton.DeleteMany(filter, options);
  310. }
  311.  
  312. public void ClearCollection<TDoc>(string collectionName)
  313. {
  314. var colleciton = GetMongoCollection<TDoc>(collectionName);
  315. var inddexs = colleciton.Indexes.List();
  316. List<IEnumerable<BsonDocument>> docIndexs = new List<IEnumerable<BsonDocument>>();
  317. while (inddexs.MoveNext())
  318. {
  319. docIndexs.Add(inddexs.Current);
  320. }
  321. var mongoDatabase = GetMongoDatabase();
  322. mongoDatabase.DropCollection(collectionName);
  323.  
  324. if (!CollectionExists(mongoDatabase, collectionName))
  325. {
  326. CreateCollection<TDoc>(collectionName);
  327. }
  328.  
  329. if (docIndexs.Count > 0)
  330. {
  331. colleciton = mongoDatabase.GetCollection<TDoc>(collectionName);
  332. foreach (var index in docIndexs)
  333. {
  334. foreach (IndexKeysDefinition<TDoc> indexItem in index)
  335. {
  336. try
  337. {
  338. colleciton.Indexes.CreateOne(indexItem);
  339. }
  340. catch
  341. { }
  342. }
  343. }
  344. }
  345.  
  346. }
  347. }
  348. }

对上述代码中几个特别的点进行简要说明:

1.由于MongoClient.GetDatabase 获取DB、MongoClient.GetCollection<TDoc> 获取文档(也可称为表)的方法 都有一个特点,即:如果指定的DB名称、Collection名称不存在,则会直接创建,但有的时候可能是因为DB名称、Collection名称写错了导致误创建了的DB或Collection,那就引起不必要的麻烦,故在MongoDbCsharpHelper类类内部封装了两个私有的方法:DatabaseExists(判断DB是否存在,如是连接的账号没有检索DB的权限可能会报错,故代码中加了直接返回true)、CollectionExists(判断Collection是否存在);

2.每个CRUD方法,我都分别重载了两个方法,一个是无需指定Collection名称,一个是需要指定Collection名称,为什么这么做呢?原因很简单,因为有时Collection的结构是相同的但又是不同的Collection,这时TDoc是同一个实体类,但collectionName却是不同的;

3.分页查询的时候如果Collection的数据量比较大,那么就会报类似错误:exception: Sort exceeded memory limit of 104857600 bytes, but did not opt in to external sorting. Aborting operation. Pass allowDiskUse:true,根据报错提示,我们在查询大数据量时增加AggregateOptions对象,如: colleciton.AsQueryable(new AggregateOptions { AllowDiskUse = true })

4.ClearCollection清除Collection的所有数据,如果Collection的数据量非常大,那么直接使用colleciton.DeleteMany可能需要很久,有没有类似SQL SERVER 的truncate table的方法呢?经过多方论证,很遗憾并没有找到同类功能的方法,只有DropCollection方法,而这个DropCollection方法是直接删除Collection,当然包括Collection的所有数据,效率也非常高,但是由于是Drop,Collection就不存在了,如果再访问有可能会报Collection不存在的错误,那有没有好的办法解决了,当然有,那就是先DropCollection 然后再CreateCollection,最后别忘了把原有的索引插入到新创建的Collection中,这样就实现了truncate 初始化表的作用,当然在创建索引的时候,有的时候可能报报错(如:_id),因为_id默认就会被创建索引,再创建可能就会报错,故colleciton.Indexes.CreateOne外我加了try catch,如果报错则忽略。

5.CreateCollection(创建集合)、CreateCollectionIndex(创建集合索引)因为有的时候我们需要明确的去创建一个Collection或对已有的Collection创建索引,如果通过shell命令会非常不方便,故在此封装了一下。

使用示例如下:

  1. var mongoDbHelper = new MongoDbCsharpHelper("MongoDbConnectionString", "LogDB");
  2.  
  3. mongoDbHelper.CreateCollection<SysLogInfo>("SysLog1",new[]{"LogDT"});
  4.  
  5. mongoDbHelper.Find<SysLogInfo>("SysLog1", t => t.Level == "Info");
  6.  
  7. int rsCount=0;
  8. mongoDbHelper.FindByPage<SysLogInfo, SysLogInfo>("SysLog1",t=>t.Level=="Info",t=>t,1,20,out rsCount);
  9.  
  10. mongoDbHelper.Insert<SysLogInfo>("SysLog1",new SysLogInfo { LogDT = DateTime.Now, Level = "Info", Msg = "测试消息" });
  11.  
  12. mongoDbHelper.Update<SysLogInfo>("SysLog1",new SysLogInfo { LogDT = DateTime.Now, Level = "Error", Msg = "测试消息2" },t => t.LogDT==new DateTime(1900,1,1));
  13.  
  14. mongoDbHelper.Delete<SysLogInfo>(t => t.Level == "Info");
  15.  
  16. mongoDbHelper.ClearCollection<SysLogInfo>("SysLog1");

基于MongoDb官方C#驱动封装MongoDbCsharpHelper类(CRUD类)的更多相关文章

  1. 适用于app.config与web.config的ConfigUtil读写工具类 基于MongoDb官方C#驱动封装MongoDbCsharpHelper类(CRUD类) 基于ASP.NET WEB API实现分布式数据访问中间层(提供对数据库的CRUD) C# 实现AOP 的几种常见方式

    适用于app.config与web.config的ConfigUtil读写工具类   之前文章:<两种读写配置文件的方案(app.config与web.config通用)>,现在重新整理一 ...

  2. 封装对MongoDB数据库的增删改查访问方法(基于MongoDB官方发布的C#驱动)

    本文利用MongoDB官方发布的C#驱动,封装了对MongoDB数据库的增删改查访问方法.先用官方提供的mongo-csharp-driver ,当前版本为1.7.0.4714 编写数据库访问帮助类 ...

  3. 基于mongodb的python之增删改查(CRUD)

    1,下载mongodb的python驱动,http://pypi.python.org/pypi/pymongo/,根据操作系统和python平台版本选择相应的egg或exe安装. 2,新建一个py脚 ...

  4. Go MongoDB官方数据库驱动之增删改查

    package main import ( "context" "fmt" "log" "go.mongodb.org/mongo ...

  5. MongoDB官方C#驱动中查询条件Query用法

    Query.All("name", "a", "b");//通过多个元素来匹配数组 Query.And(Query.EQ("nam ...

  6. MongoDB官方C#驱动的AsQueryable踩到坑了

    collection.AsQueryable().Where()有4个重载,分别是: public static IQueryable<TSource> Where<TSource& ...

  7. 基于mongodb的java之增删改查(CRUD)

    1,下载驱动https://github.com/mongodb/mongo-java-driver/downloads,导入工程java中 2,建立测试代码 import java.net.Unkn ...

  8. 【MongoDB】 基于C#官方驱动2.2版的封装类

    一.前言 最近项目中要用到MongoDB,因此实现做了不少的调研.发现网上很多现有关于MongoDB C#官方驱动的调用方法都是基于1.8版本的,已经不是用了最新的2.2版本.因此我在基于C#官方驱动 ...

  9. 基于Mongodb的轻量级领域驱动框架(序)

    混园子也有些年头了,从各个大牛那儿学了很多东西.技术这东西和中国的料理一样,其中技巧和经验,代代相传(这不是舌尖上的中国广告).转身回头一望,几年来自己也积累了一些东西,五花八门涉猎到各种方向,今日开 ...

随机推荐

  1. 选择客栈noip2011

    哈,没想到吧.今天居然有两篇(算什么,厕所读物吗 选择客栈 本题的更优解请跳转zt 这题11年,刚改2day. 对于30% 的数据,有 n ≤100: 对于50% 的数据,有 n ≤1,000: 对于 ...

  2. java.util.ArrayList、java.util.vector和java.util.LinkedList (JDK 1.8.0_111)

    一.java.util.ArrayList 1.1 ArrayList 继承结构 ArrayList实现了RandomAccess,可以随机访问(其实就是通过数组下标访问):实现了Cloneable, ...

  3. Java---实现邮件发送

    实现发送邮件的发送必须有前提条件: 在qq邮件中开启POP3/SMTP服务,如下图所示(为本人邮件设置): 开启后会得到一个授权码.代码中会用到 需要的包: 百度网盘(包+源码):链接: https: ...

  4. JSP具体篇——response对象

    response对象 response对象用于响应client请求,向客户输出信息. 他封装了JSP产生的响应,并发送到client以响应client请求. 1.重定向网页 使用response对象的 ...

  5. M03 利用Accord 进行机器学习的第一个小例子

    01 安装 Visual studio 2017. 不具备安装这个的话,也可安装,Microsoft Visual Studio Express (or equivalent) 02 创建 C# 的 ...

  6. 自学Zabbix3.6.4-触发器triggers dependencies依赖关系

    有时,一个主机的可用性取决于另一个主机.如果路由器坏了,某个路由器后面的服务器就会变得不可访问.对于两个主机都配置了触发器,您可能会收到两个主机的通知,而只有路由器是有罪的一方.这是主机之间的一些依赖 ...

  7. immutable.js 更新数组(mergeDeepWith)

    使用情境: 技术栈为:react + redux + antd (reducer中处理数据使用了immutable.js). 问题:如下图,做一个搜索功能,form表单每改变一次,都会调用一个upda ...

  8. CSS实现文字换行

    强制不换行:div{ white-space:nowrap; } 自动换行: div{ word-wrap:break-word; word-break:normal; } 强制不换行 white-s ...

  9. intellij IDEA里各图标对应的文件类型

    本篇内容为大家提供的是IntelliJ IDEA 使用教程中的常见文件类型的图标介绍,IntelliJ IDEA是java语言开发的集成环境,IntelliJ在业界被公认为最好的java开发工具之一, ...

  10. log4go的输出优化

    又看了一些golang的日志包和相关的文章,仔细阅读了go 1.9.2系统提供的log和go-log,产生了对log4go的日志输出进行优化的想法. 结构化与multiwriter log使用mult ...