前邊我們已經使用mongo shell進行增刪查改和聚合操作,這一篇簡單介紹如何使用C#驅動MongoDB。C#驅動MongoDB的本質是將C#的操作程式碼轉換為mongo shell,驅動的API也比較簡單明瞭,方法名和js shell的方法名基本都保持一致,熟悉mongo shell後學習MongoDB的C#驅動是十分輕鬆的,直接看幾個栗子吧。
0.準備測試資料
使用js shell新增一些測試資料,如下:
use myDb db.userinfos.insertMany([ {_id:1, name: "張三", age: 23,level:10, ename: { firstname: "san", lastname: "zhang"}, roles: ["vip","gen" ]}, {_id:2, name: "李四", age: 24,level:20, ename: { firstname: "si", lastname: "li"}, roles:[ "vip" ]}, {_id:3, name: "王五", age: 25,level:30, ename: { firstname: "wu", lastname: "wang"}, roles: ["gen","vip" ]}, {_id:4, name: "趙六", age: 26,level:40, ename: { firstname: "liu", lastname: "zhao"}, roles: ["gen"] }, {_id:5, name: "田七", age: 27, ename: { firstname: "qi", lastname: "tian"}, address:'北京' }, {_id:6, name: "周八", age: 28,roles:["gen"], address:'上海' } ])
1 新增(InsertOne,InsertMany)
首先建立一個Console應用程式,使用命令 Install-Package MongoDB.Driver 新增C#的驅動包,然後就可以使用C#操作MongoDB資料庫了,看一個新增的栗子:
class Program { static void Main(string[] args) { //連線資料庫 var client = new MongoClient("mongodb://192.168.70.131:27017"); //獲取database var mydb = client.GetDatabase("myDb"); //獲取collection var collection = mydb.GetCollection<BsonDocument>("userinfos"); //待新增的document var doc = new BsonDocument{ { "_id",7 }, { "name", "吳九" }, { "age", 29 }, { "ename", new BsonDocument { { "firstname", "jiu" }, { "lastname", "wu" } } } }; //InsertOne()新增單條docment collection.InsertOne(doc); } }
執行完成後,檢視在RoboMongo中查詢,看到已經新增成功了:
我們也可以是用 collection.InsertMany(IEnumerable<BsonDocument> docs) 來批量新增docment,這裡就不再演示了。
2 查詢(Find,Filter,Sort,Projection)
1.簡單查詢(Find、Filter)
栗子:查詢name=“吳九"的記錄
//Fileter用於過濾,如查詢name = 吳九的第一條記錄 var filter = Builders<BsonDocument>.Filter; //Find(filter)進行查詢 var doc = collection.Find(filter.Eq("name","吳九")).FirstOrDefault(); Console.WriteLine(doc);
查詢結果如下:
如果我們想查詢所有的記錄,可以設定過濾器為空,程式碼為: var docs = collection.Find(filter.Empty).ToList();
2.AND查詢
栗子:查詢年齡大於25且小於28的記錄
//查詢25<age<28的記錄 var filter = Builders<BsonDocument>.Filter; var docs = collection.Find(filter.Gt("age", 25) & filter.Lt("age", 28)).ToList(); docs.ForEach(d => Console.WriteLine(d));
查詢結果如下:
3 OR查詢
栗子:查詢年齡小於25或年齡大於28的記錄
//查詢age<25或age>28的記錄 var filter = Builders<BsonDocument>.Filter; var docs = collection.Find(filter.Lt("age", 25) | filter.Gt("age", 28)).ToList(); docs.ForEach(d => Console.WriteLine(d));
查詢結果如下:
4 欄位存在(Exists)
栗子:查詢包含address欄位的所有記錄
//查詢存在address欄位的記錄 var filter = Builders<BsonDocument>.Filter; var docs = collection.Find(filter.Exists("address")).ToList(); docs.ForEach(d => Console.WriteLine(d));
查詢結果如下:
4 排序(Sort)
栗子:查詢年齡小於26歲的記錄,並按年齡倒序排列
//查詢age<26的記錄,按年齡倒序排列 var filter = Builders<BsonDocument>.Filter; var sort = Builders<BsonDocument>.Sort; var docs = collection.Find(filter.Lt("age",26))//過濾 .Sort(sort.Descending("age")).ToList();//按age倒序 docs.ForEach(d => Console.WriteLine(d));
查詢結果如下:
5 查詢指定欄位(Projection)
MongoDB查詢會預設返回_id欄位,如果要不返回_id欄位可以使用Exclude("_id")將其排除。栗子:查詢年齡小於26歲記錄的name和age
//查詢age<26的記錄 var project = Builders<BsonDocument>.Projection; var filter = Builders<BsonDocument>.Filter; var docs = collection.Find(filter.Lt("age", 26))//過濾 .Project(project.Include("name")//包含name .Include("age")//包含age .Exclude("_id")//不包含_id ).ToList(); docs.ForEach(d => Console.WriteLine(d))
查詢結果:
3 修改(UpdateOne,UpdateMany)
1 修改單條記錄(UpdateOne)
修改符合過濾條件的第一條記錄,栗子:將張三的年齡改成18歲
var filter = Builders<BsonDocument>.Filter; var update = Builders<BsonDocument>.Update; var project = Builders<BsonDocument>.Projection; //將張三的年齡改成18 collection.UpdateOne(filter.Eq("name", "張三"), update.Set("age", 18)); //查詢張三的記錄 var doc = collection.Find(filter.Eq("name", "張三")) .Project(project.Include("age").Include("name")) .FirstOrDefault(); Console.WriteLine(doc);
執行結果:
2 修改多條記錄(UpdateMany)
UpdateMany會修改所有符合過濾條件的記錄,栗子:將所有年齡小於25的記錄標記為young(如果沒有mark欄位會自動新增)
var filter = Builders<BsonDocument>.Filter; var update = Builders<BsonDocument>.Update; var project = Builders<BsonDocument>.Projection; //將所有年齡小於25的記錄標記為young(如果沒有mark欄位會自動新增) UpdateResult reulst=collection.UpdateMany(filter.Lt("age",25), update.Set("mark", "young")); if (reulst.IsModifiedCountAvailable) { Console.WriteLine($"符合條件的有{reulst.MatchedCount}條記錄"); Console.WriteLine($"一共修改了{reulst.ModifiedCount}條記錄"); //查詢修改後的記錄 var docs = collection.Find(filter.Empty) .Project(project.Include("age").Include("name").Include("mark")) .ToList(); docs.ForEach(d => Console.WriteLine(d)); } else { Console.WriteLine("無修改操作!"); }
查詢結果如下,可以看到age<25的記錄的mark欄位值為young:
4 刪除(DeleteOne和DeleteMany)
刪除操作比較簡單,DeleteOne用於刪除符合過濾條件的第一條記錄,DeleteMany用於刪除所有符合過濾條件的記錄。
1 刪除單條記錄(DeleteOne)
栗子:刪除名字為張三的記錄
var filter = Builders<BsonDocument>.Filter; var project = Builders<BsonDocument>.Projection; //刪除名字為張三的記錄 collection.DeleteOne(filter.Eq("name", "張三")); var docs = collection.Find(filter.Empty) .Project(project.Include("age").Include("name").Include("mark")) .ToList(); docs.ForEach(d => Console.WriteLine(d));
執行結果如下,我們看到張三的記錄已經被刪除了:
2 刪除多條記錄(DeleteMany)
栗子:刪除所有年齡大於25歲的記錄
var filter = Builders<BsonDocument>.Filter; var project = Builders<BsonDocument>.Projection; //刪除age>25的記錄 DeleteResult result= collection.DeleteMany(filter.Gt("age", 25)); Console.WriteLine($"一共刪除了{result.DeletedCount}條記錄"); var docs = collection.Find(filter.Empty) .Project(project.Include("age").Include("name").Include("mark")) .ToList(); docs.ForEach(d => Console.WriteLine(d));
執行結果如下,所有年齡大於25歲的記錄都被刪除了:
5 型別對映
1 簡單栗子
有時候我們要讓查詢的結果對映到我們的實體類中去,實現這個需求也十分簡單,mongoDB支援自動對映,直接使用泛型即可,看一個栗子:
class Program { static void Main(string[] args) { //連線資料庫 var client = new MongoClient("mongodb://192.168.70.133:27017"); //獲取database var mydb = client.GetDatabase("myDb"); //獲取collection var collection = mydb.GetCollection<Userinfo>("userinfos"); var filter = Builders<Userinfo>.Filter; var sort = Builders<Userinfo>.Sort; List<Userinfo> userinfos = collection.Find(filter.Lt("age", 25)) //查詢年齡小於25歲的記錄 .Sort(sort.Descending("age")) //按年齡進行倒序 .ToList(); //遍歷結果 userinfos.ForEach(u => Console.WriteLine($"姓名:{u.name},年齡:{u.age},英文名:{u.ename.firstname} {u.ename.lastname}")); Console.ReadKey(); } } /// <summary> /// 使用者類 /// </summary> public class Userinfo { public int _id { get; set; }//id public string name { get; set; }//姓名 public int age { get; set; }//年齡 public int level { get; set; }//等級 public Ename ename { get; set; }//英文名 public string[] roles { get; set; }//角色 public string address { get; set; }//地址 } /// <summary> /// 英文名 /// </summary> public class Ename { public string firstname { get; set; } public string lastname { get; set; } }
執行結果如下:
2 常用屬性
上邊的栗子僅僅用了基本的自動化對映,使用基本的自動化對映時:類和Bson中的欄位必須嚴格一致(_id除外,可以自動對映到_id/id/Id),且Bson中的每一個欄位在實體類中都必須有一個對應的欄位,不然就會丟擲異常,這就造成我們可能要寫一個非常龐大的實體類,而且類中的欄位命名也要嚴格和Bson中的欄位一致。這些限制對我們開發來說是不能接受的,這裡我們採用mongoDriver中的一些屬性改進一下上邊的程式碼,如下:
class Program { static void Main(string[] args) {//連線資料庫 var client = new MongoClient("mongodb://192.168.70.133:27017"); //獲取database var mydb = client.GetDatabase("myDb"); //獲取collection var collection = mydb.GetCollection<Userinfo>("userinfos"); var filter = Builders<Userinfo>.Filter; var sort = Builders<Userinfo>.Sort; List<Userinfo> userinfos = collection.Find(filter.Lt("age", 25)) //查詢年齡小於25歲的記錄 .Sort(sort.Descending("age")) //按年齡進行倒序 .ToList(); //遍歷結果 userinfos.ForEach(u => { Console.WriteLine($"編號:{u.userId},姓名:{u.name},年齡:{u.age},英文名:{u.ename?.ming} {u.ename?.xing},性別:{u.gender}"); Console.WriteLine($"其他屬性:{u.otherprops}"); Console.WriteLine(); }); Console.ReadKey(); } } /// <summary> /// 使用者類 /// </summary //[BsonIgnoreExtraElements] public class Userinfo { [BsonId] public int userId { get; set; }//id public string name { get; set; }//姓名 public int age { get; set; }//年齡 public Ename ename { get; set; }//英文名 [BsonDefaultValue('男')] public char gender { get; set; } [BsonIgnore] public string nickname { get; set; }//暱稱 [BsonExtraElements] public BsonDocument otherprops { get; set; }//其他屬性 } /// <summary> /// 英文名 /// </summary> public class Ename { [BsonElement("firstname")] public string ming { get; set; } [BsonElement("lastname")] public string xing { get; set; } }
執行結果如下:
這裡用到了幾個常用的屬性,作用如下:
BsonId修飾的欄位對應BsonDocument中的_id;
BsonDefaultValue(value)用於指定預設值;
BsonIgnore表示不對映,即使BsonDocument中包含該欄位也不會賦值給屬性;
BsonExtraElements修飾的欄位用於儲存沒有對映到類中的其他屬性;
BsonElement可以指定修飾的屬性對映到BsonDocument中的哪個欄位,
還有一些其他的屬性,具體可以參考官方文件。
3 MongoDB使用Linq查詢
MongoDB的驅動支援Linq查詢,用法十分簡單,引用 usingMongoDB.Driver.Linq; 後,使用 collection.AsQueryable() 獲取IMongoQueryable<T>例項,然後就可以使用Linq對這個IMongoQueryable<T>進行查詢了。
使用過EF的小夥伴應該都瞭解IQueryable+Linq的查詢預設不是將整個結果集立即載入到記憶體中,而是延遲載入的,即只有使用結果時(如 在執行First,Last,Single,Count,ToList等)才會將Linq轉換成Sql,在資料庫中執行查詢操作。類似的,在使用IMongoQueryable<T>+Linq進行查詢時預設也是延遲載入的,在需要使用查詢結果時,驅動會將Linq轉換成聚合管道命令(aggregation pipeline),如Linq中的Where被轉換成$watch,Join轉換為$lookup,Skip和Take轉換為$skip和$limit等等,然後在Mongodb中執行這些管道命令獲取結果,看一個栗子我們就會輕鬆地掌握了。
首先新增一些測試資料:
//新增學生資料 db.students.insertMany([ {"no":1, "stuName":"jack", "age":23, "classNo":1}, {"no":2, "stuName":"tom", "age":20, "classNo":2}, {"no":3, "stuName":"hanmeimei", "age":22, "classNo":1}, {"no":4, "stuName":"lilei", "age":24, "classNo":2} ]) //新增班級資料 db.classxes.insertMany([ {"no" : 1,"clsName" : "A班"}, {"no" : 2,"clsName" : "B班"} ])
這裡查詢了兩組資料:①基本查詢:查詢年齡大於22歲的學生;②連線查詢:查詢各個學生的學號、姓名、班級名。栗子比較簡單,直接看程式碼吧
static void Main(string[] args) { //連線資料庫 var client = new MongoClient("mongodb://192.168.70.133:27017"); //獲取database var mydb = client.GetDatabase("myDb"); //獲取collection var stuCollection = mydb.GetCollection<Student>("students"); var clsCollection = mydb.GetCollection<Classx>("classes"); //查詢年齡大於22的學生 Console.WriteLine("-------------查詢年齡大於22的學生列表--------------"); //1.query語法 List<Student> stuList1 = (from stu in stuCollection.AsQueryable() where stu.age > 22 select stu).ToList(); //2.點語法 List<Student> stuList2 = stuCollection.AsQueryable().Where(s => s.age > 22).ToList(); stuList1.ForEach(stu => Console.WriteLine($"姓名:{stu?.stuName}, 年齡:{stu?.age}")); Console.WriteLine(); //表連線查詢,查詢各個學生的班級名 Console.WriteLine("-------------表連線,查詢學生的班級名----------------"); //1.query語法 var result1 = from stu in stuCollection.AsQueryable() join cls in clsCollection.AsQueryable() on stu.classNo equals cls.no select new { stuno = stu.no, stu.stuName, cls.clsName }; //2.點語法 var result2 = stuCollection.AsQueryable().Join( clsCollection.AsQueryable(), stu => stu.classNo, cls => cls.no, (stu, cls) => new { stuno=stu.no, stu.stuName, cls.clsName } ); //遍歷結果 foreach (var item in result1) { Console.WriteLine($"學號:{item.stuno}, 姓名:{item.stuName}, 班級:{item.clsName}"); } Console.ReadKey(); } } /// <summary> /// 學生類 /// </summary public class Student { public int no { get; set; }//學號 public string stuName { get; set; }//姓名 public int age { get; set; }//年齡 public int classNo { get; set; }//班級編號 [BsonExtraElements] public BsonDocument others { get; set; } } /// <summary> /// 班級類 /// </summary> public class Classx { public int no { get; set; }//班級編號 public string clsName { get; set; }//班級名 [BsonExtraElements] public BsonDocument others { get; set; } }
執行結果如下:
小結
本篇簡單介紹了C#驅動mongoDB進行CRUD操作,C#驅動功能十分豐富,幾乎實現了所有的Mongo shell功能,這裡就不再過多介紹了,有興趣的小夥伴可以看看官方的文件。如果文中有錯誤的話,希望大家可以指出,我會及時修改,謝謝。