为了账号安全,请及时绑定邮箱和手机立即绑定

.net core 2x 系列文章之-使用MongoDb并进行简单封装

标签:
Java

为什么要在.net 项目中使用NoSQL?其实这是个历史遗留问题. 最近一年用express+mongodb架构做了不少工程, 不亦乐乎, 但当项目上线时, 悲哀的发现这些脚本语言的一大特点就是难以部署. 这个话题可以展开讲: 脚本/弱类型语言不适合做大工程.
所以对其中的一个工程, 就有了重写的念头. 但是数据已经在mongo中, 迁移到关系型数据库想想就头疼. 最终决定还是mongodb吧.
看了很多各种教程, 都是helloworld, 大型项目不可能不分层, 吐槽一下MongoDB的官网文档真是很屎. 没有多少例子.今天下午, 琢磨了一下.net core和mongodb的操作实践, 算是有点心得,记下来吧.

0. 环境

  • .net core v2.2

  • mongodb v4.0

  • visual studio community 2017

  • mongodb.driver v2.7.2

1. 起项目

  • 新建.net core api 工程 , nuget 搜索 Mongodb, 下载安装MongoDB.Driver, 注意其中已经包含了MongoDB.Core, 不需要重复下载:

    webp

    image.png

2. 规划

  • POCO模型类: Domain文件夹, 所有模型类都继承Entity接口

  • 领域类: Repository文件夹, 包含数据上下文定义接口IContext和抽象操作接口IRepository
    不愿意弄太多文件夹, 这两个就够了

    webp

    image.png

3. 开码

  • 写一个空的Entity接口,方便模型类继承:

    public interface Entity
    {
    }
  • 写一个User POCO类测试, 继承Entity:

using MongoDB.Bson;using MongoDB.Bson.Serialization.Attributes;using System;using System.Collections.Generic;
   [BsonIgnoreExtraElements]    /// <summary>
    /// User POCO
    /// </summary>
    public class User:Entity
    {
        [BsonId]
        [BsonRepresentation(BsonType.ObjectId)]        public string Id { get; set; }
        [BsonElement("username")]        public string Username { get; set; }
        [BsonElement("password")]        public string Password { get; set; }
        [BsonElement("realName")]        public string RealName { get; set; }
    }

上面的一些标签有必要说一下:BsonIgnoreExtraElements 是忽略mongodb内部自动产生的一些字段, 打开mongodb就知道:比如:

webp

image.png


类似这样的, 你的POCO类中没有这个字段就会报错.
BsonId告诉说这个字段是主键, 默认是ObjectId类型.
BsonRepresentation(BsonType.ObjectId)这个标签很有用, 在后面Update, findbyid的时候, 由于前台传过来的是字符串, 没法和数据库中ObjectId类型的主键进行比较. 加上这个就可以解决这个问题.
BsonElement("username")是在数据库中的字段名.


  • Repository文件夹下建立IContext接口:

using BioVR.Backend.Domain;using MongoDB.Driver;    public interface IContext<T> where T:Entity
    {
       IMongoCollection<T> Entities { get;}
    }

这个接口主要是规定所有的Contex实现类中都要有IMongoCollection类型字段, 俗话说得好,接口即规范.

  • UserContext实现类

    public class UserContext : IContext<User>
    {        // IOC
        private readonly IMongoDatabase _db;        public UserContext(IOptions<Settings> options)
        {
            var client = new MongoClient(options.Value.ConnectionString);
            _db = client.GetDatabase(options.Value.Database);
             
        }        public IMongoCollection<User> Entities => _db.GetCollection<User>("users");
         
    }

这里, 我们使用.net 的依赖注入(构造函数方式)从Settings里拿到了数据库连接字符串, 并连接到了数据库, 如是, 我们必须注册settings:
打开项目目录下的appsettings.json, 添加数据库连接地址

{  "MongoDB": {    "ConnectionString": "mongodb://localhost:27017",    "Database": "yourdbname"
  },  "Logging": {    "LogLevel": {      "Default": "Warning"
    }
  },  "AllowedHosts": "*"}

然后在Startup.cs中加入Configuration:

      public IConfiguration Configuration { get; }        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            services.Configure<Settings>(
               options =>
               {
                   options.ConnectionString = Configuration.GetSection("MongoDb:ConnectionString").Value;
                   options.Database = Configuration.GetSection("MongoDb:Database").Value;
               }); 
        }

这样上面的UserContext就能拿到数据了

  • UserRepository类:

  public class UserRepository : IRepository<User>
    {        private readonly IContext<User> _context;        /// <summary>
        /// IOC
        /// </summary>
        /// <param name="context"></param>
        public UserRepository(IContext<User> context)
        {
            _context = context;
        }        public async Task<string> Create(User t)
        { 
            await  _context.Entities.InsertOneAsync(t);            return t.Id;
        }        public async Task<bool> Delete(string id)
        {
           var deleteResult =  await _context.Entities.DeleteOneAsync(x => x.Id == id);            return deleteResult.DeletedCount != 0;
        } 

        public async Task<List<User>> GetList(int skip = 0, int count = 0)
        {            try
            {
                var result = await _context.Entities.Find(x => true)
                                   .Skip(skip)
                                   .Limit(count)
                                   .ToListAsync();                return result;
            }            catch (Exception ex)
            {                throw;
            }
          
        }        public async Task<List<User>> GetListByField(string fieldName, string fieldValue)
        {
            var filter = Builders<User>.Filter.Eq(fieldName, fieldValue);
            var result = await _context.Entities.Find(filter).ToListAsync(); 
            return result;
        }        public async  Task<User> GetOneById(string id)
        {            return await _context.Entities.Find(x => x.Id.ToString() == id).FirstOrDefaultAsync();
        }        public async Task<bool> Update(User t)
        {
            var filter = Builders<User>.Filter.Eq(x=>x.Id,t.Id);
            var replaceOneResult = await _context.Entities.ReplaceOneAsync(doc => doc.Id == t.Id,t); 
            return replaceOneResult.ModifiedCount != 0;
        }
    }

这里写CURD的各个方法, 注意,除了lambda表达式,我们还可以使用Linq语法做查询.

  • UserController:

    [Route("api/[controller]")]
    [ApiController]    public class UsersController : ControllerBase
    {        private readonly IRepository<User> _userRepository;        public UsersController(IRepository<User> userRepository)
        {
            _userRepository = userRepository;
        }
        [HttpGet]        public async Task<List<User>> List()
        {            return await _userRepository.GetList();
        }
        [HttpPost]        public async Task<string> Add([FromBody] User user)
        {
            var id = await _userRepository.Create(user);            return id;
        }
        [HttpDelete("{id}")]        public async Task<bool> Delete(string id)
        {           return  await _userRepository.Delete(id);        
        }
    }

注意UserController和UserRepository类中都有依赖注入,我们必须注册这些服务, 在Startup文件中加入:

  // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            services.Configure<Settings>(
               options =>
               {
                   options.ConnectionString = Configuration.GetSection("MongoDb:ConnectionString").Value;
                   options.Database = Configuration.GetSection("MongoDb:Database").Value;
               });
            InjectRepositories(services);
        }        private void InjectRepositories(IServiceCollection services)
        {
            services.AddTransient<IContext<User>, UserContext>();
            services.AddTransient<IRepository<User>, UserRepository>();
        }

单独写一个InjectRepositories方法, 因为可能将来需要注册的服务会很多.

这样就可以了.
本文没什么特别之处, 就是觉得这样的架构比较适合项目开发, 自己记录一下, 也供大家参考,抛砖引玉.



作者:Angeladaddy
链接:https://www.jianshu.com/p/ce6fe18c2b9f


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
全栈工程师
手记
粉丝
228
获赞与收藏
996

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消