日前從公司離職,很快,還沒休息就步入瞭如今的公司,開始跟着公司的腳步走。html
公司的項目基本都是大數據的,因此在數據庫上大部分都是使用Mongodb和Redis,基本都是Nosql型的數據庫爲主。之前本身學着作過Mongodb和Redis的Demo,大致知道其怎麼去運用,只是沒有一個規範化的封裝和運用,單純是學習。如今有實戰項目了,就激起了我前進學習的心,趁着今天本身查了下一些資料,學習了借鑑了一些前輩的方法後本身也封裝了一個Mongdb的底層通用類,這裏分享出來跟你們一塊兒學習下。git
這裏主要是講我封裝的底層,不涉及到Mongodb的安裝,啓動,可視化查詢等東西,後面會附上一些參考的地址供你們一塊兒學習。github
目前mongodb提供的驅動主要有兩種:sql
1.官網驅動 下載地址:http://github.com/mongodb/mongo-csharp-driver/downloadsmongodb
2.第三方的samus驅動 下載地址:https://github.com/samus/mongodb-csharp數據庫
兩個驅動的運用本身都有使用過,我的感受官方的驅動提供的方法比較多,用起來也比較順手,並且更新度比samus的高,因此本身使用的是官方的驅動。express
主要使用下面的兩個dll服務器
MongoDB.dll 驅動的主要程序多線程
MongoDB.GridFS.dll 用於存儲大文件。併發
基本的增刪改查代碼以下:
//數據庫鏈接字符串 const string strconn = "mongodb://127.0.0.1:27017"; //數據庫名稱 const string dbName = "cnblogs"; //定義數據庫 MongoDatabase db; /// <summary> /// 打開數據庫連接 /// </summary> public void GetConnection() { //定義Mongo服務 Mongo mongo = new Mongo(strconn); //打開鏈接 mongo.Connect(); //得到數據庫cnblogs,若不存在則自動建立 db = mongo.GetDatabase(dbName) as MongoDatabase; } /// <summary> /// 添加數據 /// </summary> public void Insert() { var col = db.GetCollection<Users>(); //或者 //var col = db.GetCollection("Users"); Users users = new Users(); users.Name = "xumingxiang"; users.Sex = "man"; col.Insert(users); } /// <summary> /// 更新數據 /// </summary> public void Update() { var col = db.GetCollection<Users>(); //查出Name值爲xumingxiang的第一條記錄 Users users = col.FindOne(x => x.Name == "xumingxiang"); //或者 //Users users = col.FindOne(new Document { { "Name", "xumingxiang" } }); users.Sex = "women"; col.Update(users, x => x.Sex == "man"); } /// <summary> /// 刪除數據 /// </summary> public void Delete() { var col = db.GetCollection<Users>(); col.Remove(x => x.Sex == "man"); ////或者 ////查出Name值爲xumingxiang的第一條記錄 //Users users = col.FindOne(x => x.Sex == "man"); //col.Remove(users); } /// <summary> /// 查詢數據 /// </summary> public void Query() { var col = db.GetCollection<Users>(); var query = new Document { { "Name", "xumingxiang" } }; //查詢指定查詢條件的所有數據 var result1 = col.Find(query); //查詢指定查詢條件的第一條數據 var result2 = col.FindOne(query); //查詢所有集合裏的數據 var result3 = col.FindAll(); }
1.數據庫配置文件
考慮到一個項目裏面可能使用到不一樣的數據庫(好比:普通數據和文件數據等分別存到不一樣數據庫中),也有可能會跨服務器查詢,因此這裏首先建立一個配置文件幫助類,主要是能夠進行多個數據庫配置,知足跨服務器,跨數據的需求。
配置格式以下:
<?xml version="1.0" encoding="utf-8" ?> <ServiceConfig> <mongodbs> <Item dbName="myDb" hostName="mongodb://127.0.0.1:27017"></Item> <Item dbName="myDb1" hostName="mongodb://127.0.0.1:27017"></Item> <Item dbName="myDb2" hostName="mongodb://127.0.0.1:27017"></Item> </mongodbs> </ServiceConfig>
Xml序列化對象類
public class ServiceConfig { [XmlArray, XmlArrayItem("Item")] public List<mongodbConfig> mongodbs { get; set; } } [XmlRoot] public class mongodbConfig { [XmlAttribute("dbName")] public string dbName { get; set; } [XmlAttribute("hostName")] public string hostName { get; set; } }
讀取配置文件管理類
public class ManagerConfig { public static string ConfigPath; //加載配置文件 static ManagerConfig() { ConfigPath = "./config.xml"; } //xml序列化後的對象 private static ServiceConfig _settings; public static ServiceConfig ServiceSettings { get { return _settings ?? (_settings = Load()); } } //加載xml序列化爲ServiceConfig對象 static ServiceConfig Load() { if (File.Exists(ConfigPath)) { using (FileStream fs = new FileStream(ConfigPath, FileMode.Open)) { XmlSerializer xs = new XmlSerializer(typeof(ServiceConfig)); //序列化爲一個對象 _settings = (ServiceConfig)xs.Deserialize(fs); } } else { throw new Exception("數據庫配置文件不存在,請檢查"); //_settings = new ServiceConfig(); } return _settings; } }
2.實體通用接口
mongodb中自己沒有自增ID的屬性,自帶有一個ObjectID,爲了統一每一個實體對象都有這個ID ,這裏創建一個通用接口和一個底層實體基類來進行規範化處理
實體接口
public interface IMongoEntity { string Id { get; } }
底層實體基類
public class BaseModel : IMongoEntity { [BsonIgnore] public string Id { get { if (_id == ObjectId.Empty) _id = ObjectId.GenerateNewId(DateTime.Now); return _id.ToString(); } } [BsonId] private ObjectId _id; }
實體類的例子(繼承於BaseModel類)
public class UserEntity : BaseModel { public string UserName { get; set; } public int Num { get; set; } //MongoDB中存儲的時間是標準時間UTC +0:00 (相差了8個小時) [BsonDateTimeOptions(Kind = DateTimeKind.Local)] public DateTime PostTime { get; set; } }
3.Mongodb通用幫助基類 (主要類)
public class MongodbBase<T> where T : class,IMongoEntity { protected MongoServer server = null; protected MongoDatabase db = null; protected MongoCollection<T> collection; protected void Init(string DbName) { var Item = ManagerConfig.ServiceSettings.mongodbs.Where(p => p.dbName == DbName).FirstOrDefault(); if (Item == null) { throw new Exception("不存在數據庫爲: " + DbName + " 的配置對象,請檢查"); } else { server = MongoDB.Driver.MongoServer.Create(Item.hostName); db = server.GetDatabase(Item.dbName); collection = db.GetCollection<T>(typeof(T).Name.Replace("Entity", "")); } } #region 查詢 /// <summary> /// 根據ID獲取對象 /// </summary> /// <param name="id"></param> /// <returns></returns> public T GetModelById(string id) { return collection.FindOneById(id); } /// <summary> /// 獲取一條記錄(自定義條件) /// </summary> /// <returns></returns> public T FirstOrDefault(Expression<Func<T, bool>> expression) { MongoDB.Driver.IMongoQuery query = Query<T>.Where(expression); return collection.FindOne(query); } /// <summary> /// 獲取一條記錄 /// </summary> /// <returns></returns> public T FirstOrDefault() { return collection.FindAll().FirstOrDefault(); } /// <summary> /// 獲取所有 /// </summary> /// <returns></returns> public List<T> FindAll() { return collection.FindAll().ToList(); } /// <summary> /// 獲取所有(自定義條件) /// </summary> /// <returns></returns> public List<T> FindAll(Expression<Func<T, bool>> expression) { MongoDB.Driver.IMongoQuery query = Query<T>.Where(expression); return collection.Find(query).ToList(); } /// <summary> /// 根據條件獲取數量 /// </summary> /// <param name="expression"></param> /// <returns></returns> public long GetCount(Expression<Func<T, bool>> expression = null) { if (expression == null) { return collection.Count(); } else { return collection.Count(Query<T>.Where(expression)); } } /// <summary> /// 根據ID判斷是否存在 /// </summary> /// <param name="id"></param> /// <returns></returns> public bool Exists(string id) { return collection.FindOneById(id) != null; } /// <summary> /// 分頁 /// </summary> /// <param name="PageIndex">總頁碼</param> /// <param name="PageSize">頁容量</param> /// <param name="RowCounts">總記錄數</param> /// <param name="expression">條件</param> /// <param name="IsAsc">是不是正序</param> /// <param name="OrderFiled">排序的字段</param> /// <returns></returns> public List<T> Page(int PageIndex, int PageSize, out long RowCounts, Expression<Func<T, bool>> expression = null, bool IsAsc = true, params string[] OrderFiled) { MongoCursor<T> mongoCursor; //條件選擇 if (expression != null) { RowCounts = collection.Find(Query<T>.Where(expression)).Count(); mongoCursor = collection.Find(Query<T>.Where(expression)); } else { RowCounts = collection.FindAll().Count(); mongoCursor = collection.FindAll(); } //排序 if (OrderFiled != null && OrderFiled.Length > 0) { //處理主鍵字段 for (int i = 0; i < OrderFiled.Length; i++) { if (OrderFiled[i].Equals("id", StringComparison.CurrentCultureIgnoreCase)) { OrderFiled[i] = "_id"; } } if (IsAsc) { mongoCursor = mongoCursor.SetSortOrder(SortBy.Ascending(OrderFiled)); } else { mongoCursor = mongoCursor.SetSortOrder(SortBy.Descending(OrderFiled)); } } return mongoCursor.SetSkip((PageIndex - 1) * PageSize).SetLimit(PageSize).ToList(); } #region 效率低,暫時不用 ///// <summary> ///// 分頁 ///// </summary> ///// <returns></returns> //public List<T> Page(int PageIndex, int PageSize, out long RowCounts, Expression<Func<T, bool>> expression = null) //{ // List<T> ret = new List<T>(); // IQueryable<T> queryable; // //條件選擇 // if (expression != null) // { // queryable = collection.Find(Query<T>.Where(expression)).AsQueryable(); // } // else // { // queryable = collection.FindAll().AsQueryable(); // } // RowCounts = queryable.Count(); // ret = queryable.Skip((PageIndex - 1) * PageSize).Take(PageSize).ToList(); // return ret; //} ///// <summary> ///// 分頁 ///// </summary> ///// <typeparam name="TKey"></typeparam> ///// <param name="PageIndex"></param> ///// <param name="PageSize"></param> ///// <param name="RowCounts"></param> ///// <param name="expression"></param> ///// <param name="orderBy"></param> ///// <param name="IsOrder"></param> ///// <returns></returns> //public List<T> Page<TKey>(int PageIndex, int PageSize, out long RowCounts, Expression<Func<T, bool>> expression = null, Expression<Func<T, TKey>> orderBy = null, bool IsOrder = true) //{ // List<T> ret = new List<T>(); // IQueryable<T> queryable; // //條件選擇 // if (expression != null) // { // queryable = collection.Find(Query<T>.Where(expression)).AsQueryable(); // } // else // { // queryable = collection.FindAll().AsQueryable(); // } // //排序 // if (orderBy != null) // { // if (IsOrder) // { // queryable = queryable.OrderBy(orderBy); // } // else // { // queryable = queryable.OrderByDescending(orderBy); // } // } // RowCounts = queryable.Count(); // ret = queryable.Skip((PageIndex - 1) * PageSize).Take(PageSize).ToList(); // return ret; //} #endregion #endregion #region 刪除 /// <summary> /// 帶條件的刪除 /// </summary> /// <param name="expression"></param> /// <returns></returns> public void Delete(Expression<Func<T, bool>> expression) { MongoDB.Driver.IMongoQuery query = Query<T>.Where(expression); var result = collection.Remove(query); } /// <summary> /// 根據模型刪除 /// </summary> /// <param name="model"></param> public void Delete(T model) { MongoDB.Driver.IMongoQuery query = Query<T>.Where(p => p.Id == model.Id); collection.Remove(query); } /// <summary> /// 根據ID刪除 /// </summary> /// <param name="Id"></param> public void Delete(string Id) { MongoDB.Driver.IMongoQuery query = Query<T>.Where(p => p.Id == Id); collection.Remove(query); } /// <summary> /// 所有刪除 /// </summary> /// <returns></returns> public void DeleteAll() { var result = collection.RemoveAll(); } #endregion #region 添加 /// <summary> /// 單模型添加 /// </summary> /// <param name="model"></param> /// <returns></returns> public void Insert(T model) { var result = collection.Insert<T>(model); } /// <summary> /// 批量添加 /// </summary> /// <param name="model"></param> /// <returns></returns> public void InsertBatch(List<T> model) { collection.InsertBatch<T>(model); } #endregion #region 修改 /// <summary> /// 修改 /// </summary> /// <param name="model"></param> /// <returns></returns> public void Update(T model) { var result = collection.Save<T>(model); } /// <summary> /// 批量修改 /// </summary> /// <param name="model"></param> public void UpdateAll(List<T> model) { model.ForEach(e => collection.Save<T>(e)); } #endregion }
4.業務類
當新建一個表(mongodb裏面叫作集合),須要對其進行操做,包括一些業務處理時。首先繼承MongodbBase類,而後使用Init方法初始化對象,以下面的UserServcices類
public class UserServices : MongodbBase<UserEntity> { public UserServices() { this.Init("myDb"); } }
5.使用
[TestClass] public class UnitTest1 { Random rd = new Random(); UserServices ubll = new UserServices(); #region 添加 [TestMethod] public void 添加() { UserEntity model = new UserEntity(); model.UserName = "Name" + rd.Next(100, 10000); model.Num = rd.Next(100, 10000); model.PostTime = DateTime.Now; ubll.Insert(model); } [TestMethod] public void 添加複雜模型() { ComplexEntity model = new ComplexEntity(); ComplexServices cbll = new ComplexServices(); model.Name = "Complex"; model.Schools = new List<School>(); model.Schools.Add(new School() { Master = new Grade() { Name = "Master" }, Name = "School", Students = new List<Student>() }); model.Schools[0].Students.Add(new Student() { Age = 22, Name = "張三" }); cbll.Insert(model); } [TestMethod] public void 批量添加() { List<UserEntity> Data = new List<UserEntity>(); for (int i = 0; i < 1000000; i++) { UserEntity model = new UserEntity(); model.UserName = "Name" + rd.Next(100, 10000); model.Num = rd.Next(100, 10000); model.PostTime = DateTime.Now; Data.Add(model); } ubll.InsertBatch(Data); } #endregion #region 修改 [TestMethod] public void 獲取單個對象_修改() { var model = ubll.FirstOrDefault(p => p.Id != ""); model.UserName = "new1"; ubll.Update(model); } [TestMethod] public void 批量修改() { var model = ubll.FindAll(); for (int i = 0; i < model.Count; i++) { model[i].UserName = "Text"; } ubll.UpdateAll(model); } #endregion #region 查詢 [TestMethod] public void 獲取所有對象() { var model = ubll.FindAll(); var count = model.Count; } [TestMethod] public void 獲取單個對象() { var model = ubll.FirstOrDefault(); var count = model.PostTime; } [TestMethod] public void 根據ID獲取對象() { var model = ubll.GetModelById("eeef22d6-7ac6-40cd-9312-59ab15fd904a"); } [TestMethod] public void 獲取所有對條件象_帶條件() { var model = ubll.FindAll(p => p.UserName.Contains("Name")); var count = model.Count; } [TestMethod] public void 分頁() { long Rows; List<UserEntity> pageDate = new List<UserEntity>(); pageDate = ubll.Page(300, 20, out Rows, p => p.Num > 1500); pageDate = ubll.Page(1, 20, out Rows, null, true, "Id"); pageDate = ubll.Page(1, 20, out Rows, null, true, "Num"); pageDate = ubll.Page(1, 20, out Rows, p => p.Num > 1500, false, "Id"); } [TestMethod] public void 獲取數量() { //不帶條件 var count = ubll.GetCount(); //帶條件 var count1 = ubll.GetCount(p => p.Num > 5000); } #endregion #region 刪除 [TestMethod] public void 刪除_自定義條件() { ubll.Delete(p => p.Num >= 2000); } [TestMethod] public void 刪除_刪除模型() { var model = ubll.FirstOrDefault(); if (model != null) { ubll.Delete(model); } } [TestMethod] public void 刪除_根據ID刪除() { ubll.Delete("ec45ea8b-a551-46eb-ad58-1b4f5f2aab25"); } [TestMethod] public void 刪除_刪除所有() { ubll.DeleteAll(); } #endregion #region 其餘 [TestMethod] public void 同時建立兩個對象_同一數據庫內() { LogServices Logbll = new LogServices(); UserEntity model = new UserEntity(); model.UserName = "Name" + rd.Next(100, 10000); model.Num = rd.Next(100, 10000); model.PostTime = DateTime.Now; ubll.Insert(model); LogEntity log = new LogEntity(); log.UserName1 = "Name" + rd.Next(100, 10000); log.Num1 = rd.Next(100, 10000); log.PostTime1 = DateTime.Now; Logbll.Insert(log); model.UserName = "Name" + rd.Next(100, 10000); model.Num = rd.Next(100, 10000); model.PostTime = DateTime.Now; ubll.Insert(model); } [TestMethod] public void 同時建立兩個對象_不一樣一數據庫內() { Log1Services Logbll = new Log1Services(); UserEntity model = new UserEntity(); model.UserName = "Name" + rd.Next(100, 10000); model.Num = rd.Next(100, 10000); model.PostTime = DateTime.Now; ubll.Insert(model); LogEntity log = new LogEntity(); log.UserName1 = "Name" + rd.Next(100, 10000); log.Num1 = rd.Next(100, 10000); log.PostTime1 = DateTime.Now; Logbll.Insert(log); model.UserName = "Name" + rd.Next(100, 10000); model.Num = rd.Next(100, 10000); model.PostTime = DateTime.Now; ubll.Insert(model); } [TestMethod] public void 當指定名稱不存在時候() { ErrorServices error = new ErrorServices(); } #endregion }
以上就是本身封裝的總體邏輯和代碼,不過這裏面還有一些不明白和不足的地方,這裏提出來,但願大神們幫我解答下:
1.返回值問題
在添,刪,改的使用,根據官網提供的驅動,都有一個WriteConcernResult對象返回,但是在測試中發現,這個返回的對象永遠都是null
2.增長ID問題
mongodb中自己沒有自增ID的屬性,自帶有一個ObjectID,若是我須要一個自增ID,是不是本身建一個ID屬性,而後在增長的時候本身控制+1?不過這樣是否性能上比較低,還要考慮多線程併發的狀況下加鎖的問題。因此不知道這塊你們是怎麼去實現的?
3.分頁效率的問題
一開始分頁我是先將結果轉爲Queryable,而後在進行操做,這個代碼裏面有這段,暫時註釋掉了,後面再博客園上看到了一個前輩的mongodb分析後,改了下分頁的方式,測試過很快,但在帶條件獲取記錄行總數的時候,發現測試300W數據下,獲取總數須要600ms的時間,不知道是我方法用錯了仍是有其餘更好的?
最後附在幾個學習的地址
mongodb入門:http://www.cnblogs.com/fish-li/archive/2011/06/26/2090800.html
官網驅動介紹:http://www.cnblogs.com/zhwl/p/3421034.html
分頁優化參考:http://www.cnblogs.com/capqueen/p/MongoDBPagination.html
源碼下載:戳這裏-》