本人爲巨杉數據庫(開源NoSQL)寫的C#驅動,支持Linq,所有開源,已提交github

1、關於NoSQL的項目需求

     這些年在作AgileEAS.NET SOA 中間件平臺的推廣、技術諮詢服務過程之中,特別是針對咱們最熟悉的醫療行業應用之中,針對大數據分析,大併發性能的需求,咱們也在慢慢的引用NoSQL技術來知足數據分析與性能等多方面的須要,也進一步完善咱們的SOA基石架構風格:php

image_thumb[11]

     在早些年,對NoSQL不是很瞭解這前,後端數據存儲都是存儲的單一的關係數據庫之上,可是在不少時間,這並非最優的,好比在醫療用戶之中針對一個病人的相關數據展現,及相關性分析,關於數據庫就不是最優的,另一個,電子病歷系統的之中的結構化/半結構化病歷文檔的存儲、檢索,以及更高級的應用,結構化病歷數據挖掘,以前使用關係數據庫存儲或者使用文件存儲,很難發揮病歷數據的科研和統計、分析需求。git

    在目前咱們的醫療信息化應用之中,咱們針對這兩部分數據都引入了NoSQL存儲,針對住院患者的領域相關性數據==》即病人聚合根對象相關數據,咱們即在關係數據庫以多表存儲病人數據以及病人相關的醫囑、費用、檢驗、檢查、護理等相關信息,同時咱們也在NoSQL數據庫存儲患者的聚合根對象:程序員

0NO5MFOQW74SFJC`@6R(@_3

    在NoSQL數據庫之中的存儲:github

~NHW)0EH_0OC$KA7~8LYITU

    另外在電子病歷應用之中,病歷文檔也是直接存入NoSQL之中。mongodb

    在接觸巨杉數據庫以前,咱們一直使用MongoDB這款NoSQL產品,這是一款廣爲人知的NoSQL產品,使用者衆多,C#的驅動也很是完善,案例也比比皆時。數據庫

3、關於巨杉(sequoiadb)數據庫

     巨杉數據庫是國人開發的一款企業級NoSQL數據庫,目前已開源,官網http://www.sequoiadb.com/
初次瞭解到巨杉(sequoiadb)數據仍是源於一個客戶,由於咱們項目一直使用MongoDB,客戶就向咱們提到巨杉(sequoiadb)數據庫,說國內有人開發了這麼一個NoSQL數據庫,而且在平安銀行有過成功應用,而且由於是國人開發,因此應該相比較MongoDB,應該能獲得官方的支持,客戶也和巨杉(sequoiadb)官方的人有過接觸,官方也答應能夠作一些支持。後端

     根據網上所公開的一些信息,巨杉(sequoiadb)數據庫和MongoDB很是的接近,都是文檔型數據庫,一樣的設計思路,集合和文檔,一樣的文檔格式,Json/Bson。
根據最近一段時間的瞭解和完善C#驅動的過程來講,相對MongoDB,巨杉(sequoiadb)提供了更加方便的圖形化部署和簡單的Web管理界面:架構

image

     如下是SequoiaDB與MongoDB及其餘NoSQL數據的功能對比:併發

     比較特別是的SequoiaDB支持事務和SQL語法,固然了,這兩點在目前狀況下咱們都使用使用過。運維

4、關於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", "hetiu@yahoo.com.cn");
            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接口,這個不科學。

5、完善改造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。

6、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:sa@127.0.0.1:2222/his"/>
        <property name="DbName" type="string" value="his"/>
      </object>

7、SequoiaDB的C#驅動源代碼託管、下載

     本人爲SequoiaDB所寫的C#驅動,已提交託管到github,項目地址https://github.com/agilelab/SequoiaDB.Charp,歡迎你們下載,也歡迎你們和本人一道完善本驅動。

8、聯繫咱們

     敏捷軟件工程實驗室,是一家研究、推廣和發展新技術,並致力於提供具備自主知識產權的業務基礎平臺軟件,以及基於業務基礎平臺開發的管理軟件的專業軟件提供商。主要業務是爲客戶提供軟件企業研發管理解決方案、企業管理軟件開發,以及相關的技術支持,管理及技術諮詢與培訓業務。

     AgileEAS.NET SOA中間件平臺自2004年秋呱呱落地一來,我就一直在逐步完善和改進,也被應用於保險、醫療、電子商務、房地產、鐵路、教育等多個應用,但一直都是以我我的在推廣,2010年由於我辭職休息,我就想到把AgileEAS.NET推向市場,讓更多的人使用。

     個人技術團隊成員都是合做多年的老朋友,由於這個平臺是免費的,因此也沒有什麼收入,都是由程序員的那種理想與信念堅持,在此我感謝一塊兒奮鬥的朋友。

團隊網站:http://www.agilelab.cn

AgileEAS.NET網站:http://www.agileeas.net

官方博客:http://eastjade.cnblogs.com

github:https://github.com/agilelab/eas

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人

郵件:james@agilelab.cn,mail.james@qq.com,

電話:18629261335。

相關文章
相關標籤/搜索