日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
談?wù)凪ongoDB的三層操作

NOSQL近來(lái)勢(shì)頭不錯(cuò),MongoDB更是其中的嬌嬌者,自己學(xué)NoSQL的時(shí)候也是參考了大量的資料,最終決定要從MongoDB入手的,最重要的原因有兩點(diǎn):1自己是簡(jiǎn)單的愛(ài)好者,一切問(wèn)題我都在想是否有簡(jiǎn)單的方法解決,寧可停下來(lái)去思考大量時(shí)間,也不愿用笨方法馬上去做,而MongoDB的操作大都很簡(jiǎn)單,2自己是JS的愛(ài)好者,沒(méi)事就喜歡拿一本js的本從頭到尾看一邊,也不管記住多少,也不管用不用得到,就是喜歡,MongoDB以BSON格式存儲(chǔ),所以操作也起來(lái)也算得心應(yīng)手!現(xiàn)在做一個(gè)項(xiàng)目正是用MongoDB做為數(shù)據(jù)庫(kù)的,一開(kāi)始沒(méi)有DAL,BLL直接訪問(wèn)數(shù)據(jù)庫(kù),然后就到UI了,而且BLL是全靜態(tài)的(我喜歡靜態(tài)方法的調(diào)用簡(jiǎn)單,但狠靜態(tài)類(lèi)的不能繼承!),當(dāng)時(shí)考慮的是用MongoDB的驅(qū)動(dòng)去操作太直白了!感覺(jué)沒(méi)必要再寫(xiě)個(gè)DAL!,后來(lái)知道我想法還是很天真的,哈哈!下面就說(shuō)現(xiàn)在的操作方式吧~

創(chuàng)新互聯(lián)公司主要從事網(wǎng)站建設(shè)、成都網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)葉集,10余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專(zhuān)業(yè),歡迎來(lái)電咨詢(xún)建站服務(wù):028-86922220

一、Module層

    [Serializable]

    public sealed class user

    {

        public ObjectId id;

        public string n;

        public int age;

        public Birthday birth;

        public sealed class Birthday

        {

            public int y;

            public int m;

            public int d;

        }

    }

咋一看,有幾個(gè)地方不規(guī)范,1類(lèi)名首字母和公開(kāi)字段沒(méi)有大寫(xiě),2公開(kāi)的字段,而沒(méi)有用屬性,3字段命名沒(méi)表達(dá)它的意思?,F(xiàn)在逐個(gè)解釋一下,類(lèi)名和字段沒(méi)大寫(xiě)首字母主要是數(shù)據(jù)庫(kù)里的命名是遵循js的,用js表示時(shí)大家一般會(huì)這樣寫(xiě):

var user={id:ObjectId("123456"),n:"loogn",age:23,birth:{y:1989,m:7,d:7}}

然而,可能有人會(huì)說(shuō)可以用MongoDB.Bson.Serialization.Attributes.BsonElement這樣一個(gè)Attribute關(guān)聯(lián)呢!不過(guò)我不會(huì)那樣做,原因就是太麻煩了!這里可能還是有疑問(wèn),留到第3個(gè)問(wèn)題說(shuō)。

公開(kāi)字段而沒(méi)有用屬性也是不合常理的,學(xué)校老師都交過(guò),不管你能不能理解,反正就是要私有化字段,想公開(kāi)請(qǐng)用屬性,哈哈!不過(guò)我想了很久還是不走尋常路了,目前為止用字段沒(méi)有出現(xiàn)過(guò)缺陷問(wèn)題,我不保證以后不會(huì),但我感覺(jué)幾率十分小,就算真的有什么問(wèn)題必需要用屬性,后面加上{get;set;}也不麻煩吧!屬性畢竟還是方法,用屬性有多余的方法調(diào)用開(kāi)銷(xiāo),而且實(shí)體類(lèi)本來(lái)就是不尋常的類(lèi),一般只表示對(duì)象狀態(tài)(用字段),屬性里如果有邏輯(就像老師常說(shuō)的年齡不能小于0且不能大于150等等!),你會(huì)放到這里做嗎?顯然你都是放在BLL里做!字段命名太短了沒(méi)有表達(dá)它的意思,其實(shí)這個(gè)可以和***個(gè)一起來(lái)說(shuō),MongoDB是無(wú)模式的,同一個(gè)合集可以保多個(gè)不規(guī)則的文檔,如user集合:

{id:1,n:"user1",desc:"我的描述"}

{id:2,n:"user2"}

 所以數(shù)據(jù)庫(kù)必須保存文檔的每一個(gè)元素的name(即id,name,desc,id,name),所以元素name越短越節(jié)省空間,本來(lái)是用name更能表達(dá)的,這里用了n,其實(shí)只要把常用的約定一下,絕大部分人都是可以接受的。

在user里還有個(gè)內(nèi)嵌類(lèi)Birthday,而這個(gè)類(lèi)大寫(xiě)了首字母,我是這樣考慮的,內(nèi)嵌類(lèi)名全部按C#命名規(guī)范,因?yàn)槿萜黝?lèi)有一個(gè)該內(nèi)嵌類(lèi)類(lèi)型的字段,這里是birth,但如果找不到合適的縮寫(xiě)怎么辦呢,直接小寫(xiě)內(nèi)嵌類(lèi)名就可以了,如內(nèi)嵌城市類(lèi)City,字段名為city就不會(huì)重復(fù)了。

二、DAL層

在這一層要寫(xiě)一個(gè)基類(lèi),完成這個(gè)基類(lèi)后,其他的各各DAL類(lèi)都是浮云了~,在寫(xiě)基類(lèi)之前有一個(gè)MongoHelper,MongoHelper很簡(jiǎn)單,直接給出代碼且不寫(xiě)解釋?zhuān)?/p>

MongoServer

 完了后就可以寫(xiě)B(tài)aseDAL了,如果沒(méi)有泛型,DAL的工作還真是索然無(wú)味,但現(xiàn)在用泛型DAL的工作有趣多了,先承上代碼:

    ///

    /// 數(shù)據(jù)訪問(wèn)層基類(lèi)

    ///

    /// 文檔實(shí)體類(lèi)

    public abstract class BaseDAL

    {

        protected internal string CollectionName {  set; get; }

        ///

        /// 設(shè)置集合名

        ///

        protected abstract string SetCollectionName();

        private MongoCollection m_collection;

        ///

        /// 根據(jù)CollectionName得到MongoCollection對(duì)象

        ///

        protected internal MongoCollection Collection

        {

            get

            {

                if (m_collection == null)

                {

                    CollectionName = SetCollectionName();

                    m_collection = MongoHelper.GetDatabase().GetCollection(CollectionName);

                }

                return m_collection;

            }

        }

        ///

        /// 根據(jù)query條件得到一個(gè)文檔對(duì)象

        ///

        /// 查詢(xún)條件

        /// 預(yù)處理方法

        ///

        public TDocument FindOne(IMongoQuery query, PreprocessHandler preprocess)

        {

            var document = Collection.FindOne(query);

            if (preprocess != null)

            {

                preprocess(ref document);

            }

            return document;

        }

        ///

        /// 把MongoCursor轉(zhuǎn)換成IList類(lèi)型

        ///

        /// 文檔游標(biāo)

        /// 預(yù)處理方法

        ///

        protected internal IList CursorToList(MongoCursor cursor, PreprocessHandler preprocess)

        {

            IList list = new List(30);

            bool isPreprocess = preprocess != null;

            foreach (TDocument document in cursor)

            {

                var doc = document;

                if (isPreprocess)

                    preprocess(ref doc);

                list.Add(doc);

            }

            return list;

        }

 

        ///

        /// 根據(jù)query查詢(xún)集合

        ///

        /// 條件

        /// 預(yù)處理方法

        ///

        public IList Find(IMongoQuery query, MongoCursorSettings cursorSettings, PreprocessHandler preprocess)

        {

            var cursor = Collection.Find(query);

            if (cursorSettings != null)

            {

                cursorSettings.Set(cursor);

            }

            var list = CursorToList(cursor, preprocess);

            return list;

        }

    }

最上面的代碼就是設(shè)置操作哪個(gè)集合,這里有一點(diǎn)感覺(jué)不爽,為什么屬性的get和set不能分別為抽象的呢?!雖然可以把整個(gè)屬性標(biāo)記為abstract,但在實(shí)現(xiàn)類(lèi)中也要寫(xiě)get和set的實(shí)現(xiàn)(set可以是空代碼塊),所以這里回歸原本用了一個(gè)SetCollectionName的抽象方法讓子類(lèi)去設(shè)置自己對(duì)應(yīng)的集合名。

當(dāng)你得到MongoCollection對(duì)象,特別是MongoCollection這樣的強(qiáng)類(lèi)型對(duì)象,BaseDAL剩下的工作也成浮云了?。ǘ际菍?duì)驅(qū)動(dòng)方法的封裝和個(gè)性化處理),如FindOne方法,用到一個(gè)委托:

public delegate void PreprocessHandler(ref T document);

有很多這樣的情況,得到一個(gè)實(shí)體后總是要先處理一下才可被UI方便的使用,如用戶(hù)頭像為空時(shí),給個(gè)默認(rèn)的,PreprocessHandler就是給BLL處理留個(gè)方便的接口啦!

這里選擇委托而不是其他的元素使程序更靈活(有匿名委托嘛,I like it!),大家注意到了吧,實(shí)體類(lèi)是按引用傳遞的,其實(shí)這里有個(gè)坑,我跳進(jìn)去了,但又爬上來(lái)了!然后這里立了個(gè)牌:"此處有坑,請(qǐng)繞道而行",以免匆忙趕路的你也栽個(gè)跟頭兒。

有這樣一個(gè)情況,如果你把一個(gè)null實(shí)體對(duì)象傳入處理方法,又在處理方法里判斷如果是null就實(shí)體化,這樣是得不到預(yù)期效果的,此null非彼null呀,實(shí)體化后方法里的型參是指向新對(duì)象了,但傳過(guò)來(lái)的實(shí)參還是指向null呢,這不是我們想要的,用ref便可以解決了,也許你會(huì)說(shuō)可以把實(shí)體對(duì)象返回呀,是的,但個(gè)人不喜歡那種寫(xiě)法,那樣處理方法***還要寫(xiě)reurn代碼,調(diào)用方法可能還得寫(xiě)代碼接收,麻煩!

FindOne例子完了,但FindOne遠(yuǎn)遠(yuǎn)沒(méi)完,你可以做各種你喜歡的重載。

再看Find得到多個(gè)文檔的方法,這里我選擇IList<實(shí)體>做為返回值,在BLL決不去操作MongoCursor,但有這樣一個(gè)問(wèn)題,設(shè)置Fields、Limit、排序等都是在MongoCursor上操作的呀,而且這些操作很可能都是從UI傳過(guò)來(lái)的,所以這里用了一個(gè)MongoCursorSettings類(lèi)封裝了這些設(shè)置:

MongoCursorSettings

代碼不用解釋?zhuān)憧梢詳U(kuò)展此類(lèi)做更多設(shè)置而不用修改Find方法。

CursorToList方法也很簡(jiǎn)單,其實(shí)把PreprocessHandler寫(xiě)在DAL層的原因就是這個(gè)方法啦,心細(xì)的你肯定發(fā)現(xiàn)了把PreprocessHandler寫(xiě)在BLL更合理,但那樣文檔集合就要多遍歷一遍,MongoCursor到IList一遍,PreprocessHandler處理IList又一遍!唉,程序員容易嘛~~~

當(dāng)然,你也可以對(duì)Find做各種你喜歡的重載,更要寫(xiě)其他方面(Insert,Update,Remove...)的方法對(duì)BaseDAL類(lèi)進(jìn)行完善。

***讓親看一下User浮云(其他浮云也是這個(gè)樣):

    public class User:BaseDAL

    {

        protected override string SetCollectionName()

        {

            return "user";

        }

    }

三、BLL層

有泛型就是意思,看BaseBLL:

    ///

    /// 業(yè)務(wù)邏輯層基類(lèi)

    ///

    /// 數(shù)據(jù)訪問(wèn)類(lèi)型

    /// 文檔模型類(lèi)型

    public abstract class BaseBLL where TDAL : DAL.BaseDAL,new()

    {

        protected TDAL dal = new TDAL();

        public TDocument FindOne(IMongoQuery query, PreprocessHandler preprocess)

        {

            return dal.FindOne(query,preprocess);

        }

    }

基本上是對(duì)DAL的一個(gè)調(diào)用,無(wú)他!直接到它的子類(lèi),因?yàn)槭沁壿媽?,比浮云多一點(diǎn),可以算是個(gè)神馬吧:

    public sealed class User : BLL.BaseBLL

    {

        public user FindOneByName(string name)

        {

            var doc = base.FindOne(Query.EQ("u", name), P1);

            return doc;

        }

        ///

        /// 保證不為null

        ///

        ///

        private void P1(ref user doc)

        {

            if (doc == null)

            {

                doc = new user();

            }

            P2(ref doc);

        }

        ///

        /// 也許可以處理嬰兒,哈哈

        ///

        ///

        private void P2(ref user doc)

        {

            if (doc != null)

            {

                doc.age = 0;

            }

        }

    }

代碼也是很簡(jiǎn)單,其實(shí)這里有一個(gè)想法,很多實(shí)體類(lèi)總是只有一種處理方法,可以在BaseBLL里寫(xiě)一個(gè)PreprocessHandler委托簽名的虛方法做為默認(rèn)處理方法, 在BaseBLL里就調(diào)用該方法,子類(lèi)需要就可重寫(xiě)它,這樣又簡(jiǎn)單了,為了方面查看,兩個(gè)類(lèi)的代碼寫(xiě)在一塊了:

        ///

        /// BaseBLL的默認(rèn)處理方法

        ///

        ///

        protected virtual void Preprocess(ref TDocument doc)

        {

            return;

        }

        ///

        /// LG.BLL.User重寫(xiě)基類(lèi)方法

        ///

        ///

        protected override void Preprocess(ref user doc)

        {

            if (doc == null)

                doc = new user();

            if (doc.birth == null)

                doc.birth = new user.Birthday();

        }

到此,BLL事例也完了,當(dāng)然,還要做更多的工作去完善。

四、UI層

這里其實(shí)沒(méi)啥說(shuō)的,為了文章完整性,簡(jiǎn)單提一下。

一般情況下UI是不會(huì)引用DAL的,但因?yàn)锽aseBLL用了泛型參數(shù),而泛型類(lèi)型在DAL里,所以UI也要引用DAL,但永遠(yuǎn)不要用DAL。

還有一點(diǎn),就是邏輯層實(shí)例化的問(wèn)題,比如在同一次Http請(qǐng)求中,很可能不小心或者避免不了new了LG.BLL.User多次,這樣做只是白白浪費(fèi)了內(nèi)存,增加GC壓力,沒(méi)一點(diǎn)好處,所以,再回到BLL層,添加這樣一個(gè)類(lèi):

    ///

    /// 為了在一次請(qǐng)求中同類(lèi)型邏輯對(duì)象只實(shí)例化一次,

    /// 只能在http請(qǐng)求上下文中使用

    ///

    public static class B

    {

        public static T Entity() where T : class, new()

        {

            string key = typeof(T).Name;

            if (HttpContext.Current != null)

            {

                var bll = HttpContext.Current.Items[key] as T;

                lock (key)

                {

                    if (bll == null)

                    {

                        bll = new T();

                        HttpContext.Current.Items[key] = bll;

                    }

                }

                return bll;

            }

            else

            {

                return new T();

            }

        }

    }

在UI或確定是有HTTP請(qǐng)求的上下文中都可以這樣調(diào)用了(當(dāng)然,如果基于其他上下文,也可以寫(xiě)一個(gè)類(lèi)似上面的實(shí)例化方法):

 User u = B.Entity();

到止完結(jié),平時(shí)寫(xiě)文章不多,表達(dá)欠佳,望親們見(jiàn)諒!


本文標(biāo)題:談?wù)凪ongoDB的三層操作
分享地址:http://m.5511xx.com/article/ccdsooj.html