自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

談?wù)凪ongoDB的三層操作

數(shù)據(jù)庫 其他數(shù)據(jù)庫 MongoDB
我們今天要寫的是MongoDB的三層操作,包括Module層、DAL層、BLL層。希望對大家有所幫助。

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

一、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;

        }

    }

 

咋一看,有幾個地方不規(guī)范,1類名首字母和公開字段沒有大寫,2公開的字段,而沒有用屬性,3字段命名沒表達它的意思。現(xiàn)在逐個解釋一下,類名和字段沒大寫首字母主要是數(shù)據(jù)庫里的命名是遵循js的,用js表示時大家一般會這樣寫:

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

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

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

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

{id:2,n:"user2"}

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

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

二、DAL層

在這一層要寫一個基類,完成這個基類后,其他的各各DAL類都是浮云了~,在寫基類之前有一個MongoHelper,MongoHelper很簡單,直接給出代碼且不寫解釋:

MongoServer

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

 

    /// <summary>

    /// 數(shù)據(jù)訪問層基類

    /// </summary>

    /// <typeparam name="T">文檔實體類</typeparam>

    public abstract class BaseDAL<TDocument>

    {

        protected internal string CollectionName {  set; get; }

 

        /// <summary>

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

        /// </summary>

        protected abstract string SetCollectionName();

 

        private MongoCollection<TDocument> m_collection;

 

        /// <summary>

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

        /// </summary>

        protected internal MongoCollection<TDocument> Collection

        {

            get

            {

                if (m_collection == null)

                {

                    CollectionName = SetCollectionName();

                    m_collection = MongoHelper.GetDatabase().GetCollection<TDocument>(CollectionName);

                }

                return m_collection;

            }

        }

 

        /// <summary>

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

        /// </summary>

        /// <param name="query">查詢條件</param>

        /// <param name="preprocess">預(yù)處理方法</param>

        /// <returns></returns>

        public TDocument FindOne(IMongoQuery query, PreprocessHandler<TDocument> preprocess)

        {

            var document = Collection.FindOne(query);

            if (preprocess != null)

            {

                preprocess(ref document);

            }

            return document;

        }

 

        /// <summary>

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

        /// </summary>

        /// <param name="cursor">文檔游標(biāo)</param>

        /// <param name="preprocess">預(yù)處理方法</param>

        /// <returns></returns>

        protected internal IList<TDocument> CursorToList(MongoCursor<TDocument> cursor, PreprocessHandler<TDocument> preprocess)

        {

            IList<TDocument> list = new List<TDocument>(30);

            bool isPreprocess = preprocess != null;

            foreach (TDocument document in cursor)

            {

                var doc = document;

                if (isPreprocess)

                    preprocess(ref doc);

                list.Add(doc);

            }

            return list;

        }

      

        /// <summary>

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

        /// </summary>

        /// <param name="query">條件</param>

        /// <param name="preprocess">預(yù)處理方法</param>

        /// <returns></returns>

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

        {

            var cursor = Collection.Find(query);

            if (cursorSettings != null)

            {

                cursorSettings.Set(cursor);

            }

            var list = CursorToList(cursor, preprocess);

            return list;

        }

 

    }

 

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

當(dāng)你得到MongoCollection對象,特別是MongoCollection<TDocument>這樣的強類型對象,BaseDAL剩下的工作也成浮云了!(都是對驅(qū)動方法的封裝和個性化處理),如FindOne方法,用到一個委托:

public delegate void PreprocessHandler<T>(ref T document);

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

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

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

FindOne例子完了,但FindOne遠遠沒完,你可以做各種你喜歡的重載。

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

MongoCursorSettings

代碼不用解釋,你可以擴展此類做更多設(shè)置而不用修改Find方法。

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

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

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

 

    public class User:BaseDAL<user>

    {

        protected override string SetCollectionName()

        {

            return "user";

        }

    }

 

 

三、BLL層

有泛型就是意思,看BaseBLL:

 

    /// <summary>

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

    /// </summary>

    /// <typeparam name="TDAL">數(shù)據(jù)訪問類型</typeparam>

    /// <typeparam name="TDocument">文檔模型類型</typeparam>

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

    {

        protected TDAL dal = new TDAL();

 

        public TDocument FindOne(IMongoQuery query, PreprocessHandler<TDocument> preprocess)

        {

            return dal.FindOne(query,preprocess);

        }

    }

 

基本上是對DAL的一個調(diào)用,無他!直接到它的子類,因為是邏輯層,比浮云多一點,可以算是個神馬吧:

 

    public sealed class User : BLL.BaseBLL<DAL.User, user>

    {

        public user FindOneByName(string name)

        {

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

            return doc;

        }

 

        /// <summary>

        /// 保證不為null

        /// </summary>

        /// <param name="doc"></param>

        private void P1(ref user doc)

        {

            if (doc == null)

            {

                doc = new user();

            }

            P2(ref doc);

        }

 

        /// <summary>

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

        /// </summary>

        /// <param name="doc"></param>

        private void P2(ref user doc)

        {

            if (doc != null)

            {

                doc.age = 0;

            }

        }

    }

 

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

 

        /// <summary>

        /// BaseBLL的默認處理方法

        /// </summary>

        /// <param name="doc"></param>

        protected virtual void Preprocess(ref TDocument doc)

        {

            return;

        }

 

        /// <summary>

        /// LG.BLL.User重寫基類方法

        /// </summary>

        /// <param name="doc"></param>

        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層

這里其實沒啥說的,為了文章完整性,簡單提一下。

一般情況下UI是不會引用DAL的,但因為BaseBLL用了泛型參數(shù),而泛型類型在DAL里,所以UI也要引用DAL,但永遠不要用DAL。

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

 

    /// <summary>

    /// 為了在一次請求中同類型邏輯對象只實例化一次,

    /// 只能在http請求上下文中使用

    /// </summary>

    public static class B

    {

        public static T Entity<T>() 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請求的上下文中都可以這樣調(diào)用了(當(dāng)然,如果基于其他上下文,也可以寫一個類似上面的實例化方法):

 User u = B.Entity<User>();

 

到止完結(jié),平時寫文章不多,表達欠佳,望親們見諒!

 

責(zé)任編輯:彭凡 來源: 博客園
相關(guān)推薦

2009-07-28 17:25:14

ASP.NET三層結(jié)構(gòu)

2011-04-19 13:53:41

三層架構(gòu)

2009-08-26 18:20:42

三層架構(gòu)

2014-02-12 10:07:07

三層交換原理

2010-03-11 10:49:45

三層交換

2013-08-14 10:08:07

TrunkVLAN三層交換

2013-01-09 11:00:20

架構(gòu)開發(fā)三層架構(gòu).NET架構(gòu)

2013-10-12 09:58:41

三層交換機三層交換原理交換機

2011-12-02 10:58:55

交換機

2014-10-11 17:06:07

交換機

2010-01-11 16:26:42

三層交換機作用

2010-03-22 15:02:19

三層交換機

2011-08-08 14:14:03

架構(gòu)

2012-02-03 09:44:33

.NET

2018-07-19 12:16:50

交換技術(shù)三層二層

2018-04-19 05:47:30

互聯(lián)網(wǎng)產(chǎn)品互聯(lián)網(wǎng)網(wǎng)絡(luò)模型

2009-07-30 13:07:49

ASP.NET中的三層

2009-08-05 10:07:20

交換機配置實驗

2009-04-30 09:15:25

三層結(jié)構(gòu)MVC架構(gòu)

2009-05-06 09:40:04

LINQWEB開發(fā)構(gòu)架
點贊
收藏

51CTO技術(shù)棧公眾號