前邊我們已經使用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>("classxes"); //查找年齡大於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功能,這里就不再過多介紹了,有興趣的小伙伴可以看看官方的文檔。如果文中有錯誤的話,希望大家可以指出,我會及時修改,謝謝。