.net core 2x 系列文章之-使用MongoDb并進行簡單封裝

為什么要在.net 項目中使用NoSQL?其實這是個歷史遺留問題. 最近一年用express+mongodb架構做了不少工程, 不亦樂乎, 但當項目上線時, 悲哀的發(fā)現(xiàn)這些腳本語言的一大特點就是難以部署. 這個話題可以展開講: 腳本/弱類型語言不適合做大工程.
所以對其中的一個工程, 就有了重寫的念頭. 但是數(shù)據(jù)已經(jīng)在mongo中, 遷移到關系型數(shù)據(jù)庫想想就頭疼. 最終決定還是mongodb吧.
看了很多各種教程, 都是helloworld, 大型項目不可能不分層, 吐槽一下MongoDB的官網(wǎng)文檔真是很屎. 沒有多少例子.今天下午, 琢磨了一下.net core和mongodb的操作實踐, 算是有點心得,記下來吧.

0. 環(huán)境

  • .net core v2.2
  • mongodb v4.0
  • visual studio community 2017
  • mongodb.driver v2.7.2

1. 起項目

  • 新建.net core api 工程 , nuget 搜索 Mongodb, 下載安裝MongoDB.Driver, 注意其中已經(jīng)包含了MongoDB.Core, 不需要重復下載:
    image.png

2. 規(guī)劃

  • POCO模型類: Domain文件夾, 所有模型類都繼承Entity接口
  • 領域類: Repository文件夾, 包含數(shù)據(jù)上下文定義接口IContext和抽象操作接口IRepository
    不愿意弄太多文件夾, 這兩個就夠了
    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內(nèi)部自動產(chǎn)生的一些字段, 打開mongodb就知道:比如:

image.png

類似這樣的, 你的POCO類中沒有這個字段就會報錯.
BsonId告訴說這個字段是主鍵, 默認是ObjectId類型.
BsonRepresentation(BsonType.ObjectId)這個標簽很有用, 在后面Update, findbyid的時候, 由于前臺傳過來的是字符串, 沒法和數(shù)據(jù)庫中ObjectId類型的主鍵進行比較. 加上這個就可以解決這個問題.
BsonElement("username")是在數(shù)據(jù)庫中的字段名.

  • Repository文件夾下建立IContext接口:
using BioVR.Backend.Domain;
using MongoDB.Driver;
    public interface IContext<T> where T:Entity
    {
       IMongoCollection<T> Entities { get;}
    }

這個接口主要是規(guī)定所有的Contex實現(xiàn)類中都要有IMongoCollection類型字段, 俗話說得好,接口即規(guī)范.

  • UserContext實現(xiàn)類
    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 的依賴注入(構造函數(shù)方式)從Settings里拿到了數(shù)據(jù)庫連接字符串, 并連接到了數(shù)據(jù)庫, 如是, 我們必須注冊settings:
打開項目目錄下的appsettings.json, 添加數(shù)據(jù)庫連接地址

{
  "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就能拿到數(shù)據(jù)了

  • 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方法, 因為可能將來需要注冊的服務會很多.

這樣就可以了.
本文沒什么特別之處, 就是覺得這樣的架構比較適合項目開發(fā), 自己記錄一下, 也供大家參考,拋磚引玉.

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末希停,一起剝皮案震驚了整個濱河市载矿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌榕堰,老刑警劉巖凤粗,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件撮胧,死亡現(xiàn)場離奇詭異刺洒,居然都是意外死亡伪节,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門鸳慈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來饱溢,“玉大人,你說我怎么就攤上這事走芋〖ɡ桑” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵翁逞,是天一觀的道長肋杖。 經(jīng)常有香客問我,道長挖函,這世上最難降的妖魔是什么状植? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上津畸,老公的妹妹穿的比我還像新娘振定。我一直安慰自己,他們只是感情好肉拓,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布后频。 她就那樣靜靜地躺著,像睡著了一般暖途。 火紅的嫁衣襯著肌膚如雪卑惜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天驻售,我揣著相機與錄音露久,去河邊找鬼。 笑死欺栗,一個胖子當著我的面吹牛毫痕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播纸巷,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼镇草,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了瘤旨?” 一聲冷哼從身側(cè)響起梯啤,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎存哲,沒想到半個月后因宇,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡祟偷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年察滑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片修肠。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡贺辰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嵌施,到底是詐尸還是另有隱情饲化,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布吗伤,位于F島的核電站吃靠,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏足淆。R本人自食惡果不足惜巢块,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一礁阁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧族奢,春花似錦姥闭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至弥姻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間掺涛,已是汗流浹背庭敦。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留薪缆,地道東北人秧廉。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像拣帽,于是被迫代替她去往敵國和親疼电。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 關于Mongodb的全面總結 MongoDB的內(nèi)部構造《MongoDB The Definitive Guide》...
    中v中閱讀 31,905評論 2 89
  • 作者:Tom Dykstra和Rick Anderson 此處提供了本教程的 Razor 頁版本减拭。 Razor 頁...
    AI云棧閱讀 4,944評論 0 4
  • 發(fā)現(xiàn) 關注 消息 iOS 第三方庫蔽豺、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,059評論 4 62
  • 上個月的一天拧粪,豆豆的媽媽因為有事兒修陡,不能去幼去兒園接豆豆,這個任務自然就落到了我的頭上可霎,作為爸爸的我平時很少去幼兒...
    劍俠火羽閱讀 237評論 0 0
  • 三里莊和龐家交界處魄鸦,有一處荷塘,是我上班的必經(jīng)之地癣朗。一看到它拾因,就讓人想起去年夏天,滿池荷花那美麗的倩影旷余。于是绢记,自開...
    一農(nóng)小語閱讀 196評論 0 1