本人為巨杉資料庫(開源NoSQL)寫的C#驅動,支援Linq,全部開源,已提交github
一、關於NoSQL的專案需求
這些年在做AgileEAS.NET SOA 中介軟體平臺的推廣、技術諮詢服務過程之中,特別是針對我們最熟悉的醫療行業應用之中,針對大資料分析,大併發效能的需求,我們也在慢慢的引用NoSQL技術來滿足資料分析與效能等多方面的需要,也進一步完善我們的SOA基石架構風格:
在早些年,對NoSQL不是很瞭解這前,後端資料儲存都是儲存的單一的關係資料庫之上,但是在很多時間,這並不是最優的,比如在醫療使用者之中針對一個病人的相關資料展示,及相關性分析,關於資料庫就不是最優的,另外一個,電子病歷系統的之中的結構化/半結構化病歷文件的儲存、檢索,以及更高階的應用,結構化病歷資料探勘,之前使用關係資料庫儲存或者使用檔案儲存,很難發揮病歷資料的科研和統計、分析需求。
在目前我們的醫療資訊化應用之中,我們針對這兩部分資料都引入了NoSQL儲存,針對住院患者的領域相關性資料==》即病人聚合根物件相關資料,我們即在關係資料庫以多表儲存病人資料以及病人相關的醫囑、費用、檢驗、檢查、護理等相關資訊,同時我們也在NoSQL資料庫儲存患者的聚合根物件:
在NoSQL資料庫之中的儲存:
另外在電子病歷應用之中,病歷文件也是直接存入NoSQL之中。
在接觸巨杉資料庫之前,我們一直使用MongoDB這款NoSQL產品,這是一款廣為人知的NoSQL產品,使用者眾多,C#的驅動也非常完善,案例也比比皆時。
三、關於巨杉(sequoiadb)資料庫
巨杉資料庫是國人開發的一款企業級NoSQL資料庫,目前已開源,官網http://www.sequoiadb.com/。
初次瞭解到巨杉(sequoiadb)資料還是源於一個客戶,因為我們專案一直使用MongoDB,客戶就向我們提到巨杉(sequoiadb)資料庫,說國內有人開發了這麼一個NoSQL資料庫,並且在平安銀行有過成功應用,並且因為是國人開發,所以應該相比較MongoDB,應該能得到官方的支援,客戶也和巨杉(sequoiadb)官方的人有過接觸,官方也答應可以做一些支援。
根據網上所公開的一些資訊,巨杉(sequoiadb)資料庫和MongoDB非常的接近,都是文件型資料庫,同樣的設計思路,集合和文件,同樣的文件格式,Json/Bson。
根據最近一段時間的瞭解和完善C#驅動的過程來說,相對MongoDB,巨杉(sequoiadb)提供了更加方便的圖形化部署和簡單的Web管理介面:
以下是SequoiaDB與MongoDB及其他NoSQL資料的功能對比:
比較特別是的SequoiaDB支援事務和SQL語法,當然了,這兩點在目前情況下我們都使用使用過。
四、關於SequoiaDB的C#驅動
SequoiaDB官方提供C、C++、JAVA、C#、php、Python驅動以及REST架構風格的介面,據官方的說法是Java的驅動很成熟,但是C#的驅動很簡單,只能支援最基本的Bson格式的介面,如下程式碼:
// Insert BsonDocument insertor = new BsonDocument(); insertor.Add("Last Name", "Lin"); insertor.Add("First Name", "Hetiu"); insertor.Add("Address", "SYSU"); BsonDocument sInsertor = new BsonDocument(); sInsertor.Add("Phone", "10086"); sInsertor.Add("EMail", "[email protected]"); insertor.Add("Contact", sInsertor); ObjectId insertID = (ObjectId)coll.Insert(insertor); Assert.IsNotNull(insertID); // Update DBQuery query = new DBQuery(); BsonDocument updater = new BsonDocument(); BsonDocument matcher = new BsonDocument(); BsonDocument modifier = new BsonDocument(); updater.Add("Age", 25); modifier.Add("$set", updater); matcher.Add("First Name", "Hetiu"); query.Matcher = matcher; query.Modifier = modifier; coll.Update(query); // Query DBCursor cursor = coll.Query(query); Assert.IsNotNull(cursor); BsonDocument bson = cursor.Next(); Assert.IsNotNull(bson); Assert.IsTrue(bson["First Name"].AsString.Equals("Hetiu")); Assert.IsTrue(bson["Age"].AsInt32.Equals(25)); // Delete BsonDocument drop = new BsonDocument(); drop.Add("Last Name", "Lin"); coll.Delete(drop); query.Matcher = drop; cursor = coll.Query(query); Assert.IsNotNull(cursor); bson = cursor.Next(); Assert.IsNull(bson);
集合查詢:
for (int i = 0; i < 10; ++i) { string date = DateTime.Now.ToString(); BsonDocument insertor = new BsonDocument(); insertor.Add("operation", "Query"); insertor.Add("date", date); coll.Insert(insertor); } BsonDocument matcher = new BsonDocument(); DBQuery query = new DBQuery(); matcher.Add("operation", "Query"); query.Matcher = matcher; query.ReturnRowsCount = 5; query.SkipRowsCount = 5; DBCursor cursor = coll.Query(query); Assert.IsNotNull(cursor); int count = 0; while (cursor.Next() != null) { ++count; BsonDocument bson = cursor.Current(); Assert.IsNotNull(bson); } Assert.IsTrue(count == 5);
官方的程式碼有點簡單,這不符合我們寫程式碼的風格,目前業務系統大量的使用物件操作和Linq處理,原始的Bson介面,這個不科學。
五、完善改造SequoiaDB的C#驅動
即然官方的驅動太簡單,不支援物件處理,也不支援Linq,很不科學,那麼應該怎麼辦呢,其實第一個觀點當然是放棄,我們原本使用MongoDB跑的好好的,為什麼要給自己找事呢,但是出於專案運維的觀點,以及支援國人產品的想法,最終決定自己完善和寫一個。
那麼如何來寫呢,當然是他山之石,可以攻玉,因為之前做MongoDB開發,原始的驅動配置我們的ORM跑起來也有一些問題,最早我們使用的非MongoDB的官方驅動,而是第三方驅動samus,不支援Decimal型別,但是我們專案之中有大量的Decimal型別,那麼辦呢,修改驅動,後來我們又換成了MongoDB的官方驅動,因為XmlIgnore標籤和Id對映的問題也認真的讀過MongoDB的官方驅動,對MongoDB的C#驅動比較熟悉。
所以完善SequoiaDB的C#的思路就變成了結合SequoiaDB的原始驅動和MongoDB的官方驅動,提供一個類似於MongoDB驅動的操作風格的驅動,在SequoiaDB驅動的基礎上提供了,直接操作C#物件的方案和支援Linq進行查詢、修改、刪除的功能。
經本人完善修改之後的驅動的操作風格如下:
Sequoiadb sdb = new Sequoiadb("192.168.23.57:50000"); sdb.Connect("", ""); //求集合空間。 var cs = sdb.GetCollecitonSpace("dbo"); //求集合。 var coll = cs.GetCollection<HFareDetail>(); //執行資料插入。 List<HFareDetail> vList =null; using (AgileHIS.Entities.DbEntities db = new AgileHIS.Entities.DbEntities()) { vList = db.HFareDetails.ToList(); //插入。 foreach (var item in vList) { coll.Insert(item); } System.Console.WriteLine(string.Format("insert {0} records", vList.Count)); System.Console.ReadLine(); } //按條件修改某一條資料的幾個屬性值。 var v1 = vList.FirstOrDefault(); v1.Name = string.Empty; v1.Cash = decimal.Zero; coll.Update(v1, p => p.ID == v1.ID); //按條件指量修改,指定某幾個必,其他屬性全部置空。 coll.Update(p => new HFareDetail { Cash = decimal.Zero, Name = string.Empty, Price = decimal.Zero }, p => p.ChargeTime >DateTime.Now.AddDays(-1)); //依據條件刪除 coll.Delete(p => p.ChargeTime > DateTime.Now.AddDays(-1)); //求Count int count = coll.AsQueryable<HFareDetail>() .Where(p => p.SourceID==0) .Count(); //Linq查詢Take\Skip。 var vList2 = coll.AsQueryable<HFareDetail>() .Where(p => p.CreateTime > DateTime.Now.Date.AddMonths(-12)) .Skip(10).Take(1000) .ToList(); System.Console.WriteLine(string.Format("query {0} records", vList.Count)); //Linq查詢過。 var vFare = coll.AsQueryable<HFareDetail>() .Where(p => p.CreateTime > DateTime.Now.Date.AddMonths(-12)) .FirstOrDefault(); System.Console.WriteLine(vFare); //Linq\聚合運算,目前因為測試驅動報錯,暫未實現 var sum = coll.AsQueryable<HFareDetail>() .Where(p => p.CreateTime > DateTime.Now.Date.AddMonths(-12)) .Sum(p => p.Cash); System.Console.ReadLine();
看看,程式碼是不是很清爽,很方便了呢,沒有了bson,只有物件,Linq。
六、SequoiaDB、MongoDB與AgileEAS.NET SOA整合
AgileEAS.NET SOA之前只支援MongoDB,最近要支援SequoiaDB,我們就得考慮對原有程式碼的相容,或者說,更希望自己的醫療系統能夠在業務上同時支援MongoDB和SequoiaDB,達到使用環境之中不管是選擇MongoDB還是選擇SequoiaDB都是同樣的程式碼,為此,我們在AgileEAS.NET SOA中介軟體之中定義了一個IStructDbProvider介面:
using System; using System.Collections.Generic; using System.Linq.Expressions; namespace EAS.Data { /// <summary> /// 結構化資料庫提供者介面定義。 /// </summary> /// <remarks> /// 為AgileEAS.NET SOA 中介軟體NoSQL資料訪問提供標準介面定義。 /// </remarks> public interface IStructDbProvider { /// <summary> /// 開啟連線。 /// </summary> void Connect(); /// <summary> /// 關閉連線。 /// </summary> void Close(); /// <summary> /// 連線是否開啟。 /// </summary> bool IsOpen { get; } /// <summary> /// 物件插入。 /// </summary> /// <typeparam name="T">物件型別。</typeparam> /// <param name="item">物件例項。</param> void Insert<T>(T item) where T : class; /// <summary> /// 物件批量插入。 /// </summary> /// <typeparam name="T">物件型別。</typeparam> /// <param name="items">物件例項。</param> void InsertBatch<T>(System.Collections.Generic.IEnumerable<T> items) where T : class; /// <summary> /// 根據條件執行更新操作。 /// </summary> /// <typeparam name="T">物件型別。</typeparam> /// <param name="updater">更新表示式。</param> /// <param name="func">查詢條件。</param> void Update<T>(Expression<Func<T, T>> updater, Expression<Func<T, bool>> func) where T : class; /// <summary> /// 根據條件執行更新操作。 /// </summary> /// <typeparam name="T">物件型別。</typeparam> /// <param name="item">更新物件。</param> /// <param name="func">查詢條件。</param> void Update<T>(T item, System.Linq.Expressions.Expression<Func<T, bool>> func) where T : class; /// <summary> /// 根據條件刪除物件。 /// </summary> /// <typeparam name="T">物件型別。</typeparam> /// <param name="func">條件表示式。</param> void Delete<T>(Expression<Func<T, bool>> func) where T : class; /// <summary> /// 求出Linq查詢表示式。 /// </summary> /// <typeparam name="T">物件型別。</typeparam> /// <returns>物件表示式包裝。</returns> IQueryableWarp<T> Linq<T>() where T : class; /// <summary> /// 根據條件查詢數制。 /// </summary> /// <typeparam name="T">物件型別。</typeparam> /// <param name="where">條件。</param> /// <param name="skip">跳過記錄數。</param> /// <param name="take">取記錄數。</param> /// <returns>查詢結構。</returns> List<T> List<T>(Expression<Func<T, bool>> where, int skip, int take) where T : class; /// <summary> /// 根據條件求單條記錄。 /// </summary> /// <typeparam name="T">物件型別。</typeparam> /// <param name="where">條件。</param> /// <returns>物件例項。</returns> T Single<T>(Expression<Func<T, bool>> where) where T : class; } }
IStructDbProvider字面意思即為結構化資料訪問提供者介面,本介面定義在EAS.MicroKernel.dll程式集之中,AgileEAS.NET SOA中介軟體同時提供了針對SequoiaDB和MongoDB資料庫的IStructDbProvider實現,EAS.Data.MongoDbProvider和EAS.Data.SequoiaDbProvider,這兩個實現類定義在EAS.Data.NoSQL.dll程式集之中。
因為統計使用了IStructDbProvider介面,我們針對SequoiaDB和MongoDB的操作處理就統計成了如下程式碼:
var vContainer = EAS.Context.ContextHelper.GetContext().Container; var dbProvider = vContainer.GetComponentInstance("StructDbProvider") as IStructDbProvider; //執行資料插入。 List<HFareDetail> vList = null; using (AgileHIS.Entities.DbEntities db = new AgileHIS.Entities.DbEntities()) { vList = db.HFareDetails.ToList(); //插入。 foreach (var item in vList) { dbProvider.Insert<HFareDetail>(item); } System.Console.WriteLine(string.Format("insert {0} records", vList.Count)); System.Console.ReadLine(); } //按條件修改某一條資料的幾個屬性值。 var v1 = vList.FirstOrDefault(); v1.Name = string.Empty; v1.Cash = decimal.Zero; dbProvider.Update<HFareDetail>(v1, p => p.ID == v1.ID); //按條件指量修改,指定某幾個必,其他屬性全部置空。 dbProvider.Update<HFareDetail>(p => new HFareDetail { Cash = decimal.Zero, Name = string.Empty, Price = decimal.Zero }, p => p.ChargeTime > DateTime.Now.AddDays(-1)); //依據條件刪除 dbProvider.Delete<HFareDetail>(p => p.ChargeTime > DateTime.Now.AddDays(-1)); //求Count using (var queryWarp = dbProvider.Linq<HFareDetail>()) { int count = queryWarp.Queryable .Where(p => p.SourceID == 0) .Count(); //Linq查詢Take\Skip。 var vList2 = queryWarp.Queryable .Where(p => p.CreateTime > DateTime.Now.Date.AddMonths(-12)) .Skip(10).Take(1000) .ToList(); System.Console.WriteLine(string.Format("query {0} records", vList.Count)); //Linq查詢過。 var vFare = queryWarp.Queryable .Where(p => p.CreateTime > DateTime.Now.Date.AddMonths(-12)) .FirstOrDefault(); System.Console.WriteLine(vFare); //Linq\聚合運算,目前因為測試驅動報錯,暫未實現 var sum = queryWarp.Queryable .Where(p => p.CreateTime > DateTime.Now.Date.AddMonths(-12)) .Sum(p => p.Cash); } System.Console.ReadLine();
具體是使用SequoiaDB還是使用MongoDB由系統配置檔案來決定,使用SequoiaDB:
<!--StructDb/SequoiaDb--> <object name="StructDbProvider" assembly="EAS.Data.NoSQL" type="EAS.Data.SequoiaDbProvider" LifestyleType="Thread"> <property name="ConnectionString" type="string" value="192.168.23.57:50000"/> <property name="UserName" type="string" value=""/> <property name="Password" type="string" value=""/> <property name="CollectionSpace" type="string" value="his"/> </object>
使用MongoDB。
<!--StructDb/MongoDb--> <object name="StructDbProvider" assembly="EAS.Data.NoSQL" type="EAS.Data.MongoDbProvider" LifestyleType="Thread"> <property name="ConnectionString" type="string" value="mongodb://sa:[email protected]:2222/his"/> <property name="DbName" type="string" value="his"/> </object>
七、SequoiaDB的C#驅動原始碼託管、下載
八、聯絡我們
敏捷軟體工程實驗室,是一家研究、推廣和發展新技術,並致力於提供具有自主智慧財產權的業務基礎平臺軟體,以及基於業務基礎平臺開發的管理軟體的專業軟體提供商。主要業務是為客戶提供軟體企業研發管理解決方案、企業管理軟體開發,以及相關的技術支援,管理及技術諮詢與培訓業務。
AgileEAS.NET SOA中介軟體平臺自2004年秋呱呱落地一來,我就一直在逐步完善和改進,也被應用於保險、醫療、電子商務、房地產、鐵路、教育等多個應用,但一直都是以我個人在推廣,2010年因為我辭職休息,我就想到把AgileEAS.NET推向市場,讓更多的人使用。
我的技術團隊成員都是合作多年的老朋友,因為這個平臺是免費的,所以也沒有什麼收入,都是由程式設計師的那種理想與信念堅持,在此我感謝一起奮鬥的朋友。
QQ:47920381,AgileEAS.NET
QQ群:113723486(AgileEAS SOA 平臺)/上限1000人
199463175(AgileEAS SOA 交流)/上限1000人
212867943(AgileEAS.NET研究)/上限500人
147168308(AgileEAS.NET應用)/上限500人
172060626(深度AgileEAS.NET平臺)/上限500人
116773358(AgileEAS.NET 平臺)/上限500人
125643764(AgileEAS.NET探討)/上限500人
193486983(AgileEAS.NET 平臺)/上限500人
郵件:[email protected],[email protected],
電話:18629261335。