你的位置:首页 > ASP.net教程

[ASP.net教程]mongdo通用类(C#版)


 

    日前从公司离职,很快,还没休息就步入了现在的公司,开始跟着公司的脚步走。

    公司的项目基本都是大数据的,所以在数据库上大部分都是使用Mongodb和Redis,基本都是Nosql型的数据库为主。以前自己学着做过Mongodb和Redis的Demo,大体知道其怎么去运用,只是没有一个规范化的封装和运用,单纯是学习。现在有实战项目了,就激起了我前进学习的心,趁着今天自己查了下一些资料,学习了借鉴了一些前辈的方法后自己也封装了一个Mongdb的底层通用类,这里分享出来跟大家一起学习下。

    这里主要是讲我封装的底层,不涉及到Mongodb的安装,启动,可视化查询等东西,后面会附上一些参考的地址供大家一起学习。

    目前mongodb提供的驱动主要有两种:

    1.官网驱动  下载地址:http://github.com/mongodb/mongo-csharp-driver/downloads

           2.第三方的samus驱动 下载地址:https://github.com/samus/mongodb-csharp

     两个驱动的运用自己都有使用过,个人感觉官方的驱动提供的方法比较多,用起来也比较顺手,而且更新度比samus的高,所以自己使用的是官方的驱动。

   

   官网驱动的简单使用

      主要使用下面的两个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();}

View Code

 

 

       封装扩展使用

       1.数据库配置文件

       考虑到一个项目里面可能使用到不同的数据库(比如:普通数据和文件数据等分别存到不同数据库中),也有可能会跨服务器查询,所以这里首先创建一个配置文件帮助类,主要是可以进行多个数据库配置,满足跨服务器,跨数据的需求。

       配置格式如下:

<??><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>

 

  

public class ServiceConfig  {    ["Item")]    public List<mongodbConfig> mongodbs { get; set; }  }  [public class mongodbConfig  {    ["dbName")]    public string dbName { get; set; }    ["hostName")]    public string hostName { get; set; }  }

View Code

   读取配置文件管理类

  public class ManagerConfig  {    public static string ConfigPath;    //加载配置文件    static ManagerConfig()    {      ConfigPath = "./config.";    }    //    private static ServiceConfig _settings;    public static ServiceConfig ServiceSettings    {      get      {        return _settings ?? (_settings = Load());      }    }    //加载    static ServiceConfig Load()    {      if (File.Exists(ConfigPath))      {        using (FileStream fs = new FileStream(ConfigPath, FileMode.Open))        {          = new typeof(ServiceConfig));          //序列化为一个对象          _settings = (ServiceConfig)xs.Deserialize(fs);        }      }      else      {        throw new Exception("数据库配置文件不存在,请检查");        //_settings = new ServiceConfig();      }      return _settings;    }  }

View Code

 

   2.实体通用接口

      mongodb中本身没有自增ID的属性,自带有一个ObjectID,为了统一每个实体对象都有这个ID ,这里建立一个通用接口和一个底层实体基类来进行规范化处理

      实体接口   

public interface IMongoEntity  {    string Id { get; }  }

View Code

      底层实体基类   

 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;  }

View Code

     实体类的例子(继承于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; }  }

View Code

 

  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  }

View Code

 

     4.业务类

      当新建一个表(mongodb里面叫做集合),需要对其进行操作,包括一些业务处理时。首先继承MongodbBase类,然后使用Init方法初始化对象,如下面的UserServcices类

public class UserServices : MongodbBase<UserEntity>  {    public UserServices()    {      this.Init("myDb");    }  }

View Code

 

     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  }

View Code

 

  以上就是自己封装的整体逻辑和代码,不过这里面还有一些不明白和不足的地方,这里提出来,希望大神们帮我解答下:

  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

 

   源码下载:戳这里-》