成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

談談MongoDB的三層操作

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

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

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

        }

    }

 

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

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

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

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

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

{id:2,n:"user2"}

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

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

二、DAL層

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

MongoServer

 完了后就可以寫BaseDAL了,如果沒有泛型,DAL的工作還真是索然無味,但現在用泛型DAL的工作有趣多了,先承上代碼:

 

    /// <summary>

    /// 數據訪問層基類

    /// </summary>

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

    public abstract class BaseDAL<TDocument>

    {

        protected internal string CollectionName {  set; get; }

 

        /// <summary>

        /// 設置集合名

        /// </summary>

        protected abstract string SetCollectionName();

 

        private MongoCollection<TDocument> m_collection;

 

        /// <summary>

        /// 根據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>

        /// 根據query條件得到一個文檔對象

        /// </summary>

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

        /// <param name="preprocess">預處理方法</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轉換成IList類型

        /// </summary>

        /// <param name="cursor">文檔游標</param>

        /// <param name="preprocess">預處理方法</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>

        /// 根據query查詢集合

        /// </summary>

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

        /// <param name="preprocess">預處理方法</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;

        }

 

    }

 

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

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

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

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

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

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

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

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

MongoCursorSettings

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

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

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

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

 

    public class User:BaseDAL<user>

    {

        protected override string SetCollectionName()

        {

            return "user";

        }

    }

 

 

三、BLL層

有泛型就是意思,看BaseBLL:

 

    /// <summary>

    /// 業務邏輯層基類

    /// </summary>

    /// <typeparam name="TDAL">數據訪問類型</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的一個調用,無他!直接到它的子類,因為是邏輯層,比浮云多一點,可以算是個神馬吧:

 

    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里就調用該方法,子類需要就可重寫它,這樣又簡單了,為了方面查看,兩個類的代碼寫在一塊了:

 

        /// <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事例也完了,當然,還要做更多的工作去完善。

 

四、UI層

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

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

還有一點,就是邏輯層實例化的問題,比如在同一次Http請求中,很可能不小心或者避免不了new了LG.BLL.User多次,這樣做只是白白浪費了內存,增加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請求的上下文中都可以這樣調用了(當然,如果基于其他上下文,也可以寫一個類似上面的實例化方法):

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

 

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

 

責任編輯:彭凡 來源: 博客園
相關推薦

2011-04-19 13:53:41

三層架構

2009-07-28 17:25:14

ASP.NET三層結構

2009-08-26 18:20:42

三層架構

2014-02-12 10:07:07

三層交換原理

2010-03-11 10:49:45

三層交換

2013-10-12 09:58:41

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

2013-08-14 10:08:07

TrunkVLAN三層交換

2013-01-09 11:00:20

架構開發三層架構.NET架構

2010-01-11 16:26:42

三層交換機作用

2011-12-02 10:58:55

交換機

2014-10-11 17:06:07

交換機

2010-03-22 15:02:19

三層交換機

2011-08-08 14:14:03

架構

2018-07-19 12:16:50

交換技術三層二層

2010-02-22 13:41:49

三層交換機

2009-04-30 09:15:25

三層結構MVC架構

2017-06-12 13:18:51

數據報表計算

2009-05-06 09:40:04

LINQWEB開發構架

2012-02-03 09:44:33

.NET

2018-04-19 05:47:30

互聯網產品互聯網網絡模型
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 婷婷综合在线 | 久久精品色欧美aⅴ一区二区 | 午夜影晥| 成人精品一区二区三区中文字幕 | 成人欧美一区二区三区黑人孕妇 | 999观看免费高清www | 99久久国产 | 日韩中文在线 | 国产成都精品91一区二区三 | 国产免费一区二区 | 久久国产一区二区三区 | 亚洲欧洲成人av每日更新 | 91在线看| 午夜www| 国产二区视频 | 在线国产一区 | 亚洲国产中文在线 | 国产综合久久 | 久久亚洲精品国产精品紫薇 | 亚洲电影一区 | 伊人伊人 | 视频三区 | 国产精品综合 | 天天射天天干 | 久久不射网 | 国产成人综合在线 | 日韩欧美一区二区三区免费观看 | 91porn在线观看 | 欧美亚洲视频在线观看 | 天天干视频| 一级黄色片免费在线观看 | 日韩av免费在线电影 | 精品一区二区三区在线观看国产 | 久久欧美精品 | 久久中文免费视频 | 亚洲三级av| 亚洲综合字幕 | 日韩欧美在线播放 | 国产精品视频一区二区三区不卡 | 视频一区二区在线观看 | 免费视频一区二区 |