一步一步搭架子(DM層與Service層)


首先分享一點自己最近的感悟:討厭你的人總可以找到理由去討厭你

 

正文開始

如果您是初次閱讀這個系列,請先去《Index & Writing Plan》查找並閱讀“架構設計系列”的前兩篇文章,順序閱讀會使您有更好的閱讀體驗

強烈推薦配合源代碼閱讀本文:點擊此處下載(可以直接運行,會在本地自動生成數據庫)

 

已經寫完了Factory的實現。在Factory中,我們使用了預編譯指令來實現了Model的切換:

#define A
#if B
using Model.B;
using DBaccess.B;
#endif
#if A
using Model.A;
using DBaccess.A;
#endif

切換Model,只需將#define A 修改為 #define B,非常方便(盡管要重新編譯,還是讓我有點不爽)

但是出現預編譯指令的地方不宜過多——事實上,已經有一處要改就已經讓我不爽了

所以,在DM層(數據操作層)與Service層(業務邏輯層)中,我們不能出現任何具體的Model的類名。

在本例中,就是DM和Service中不能出現類名:Teacher、Contact

因為每個出現了類Teacher和類Contact的地方,我們都要加上前文提到的預編譯指令。而在實際項目中,這樣做會導致切換Model要修改的地方非常多,可能會導致不可預期的錯誤

 

那么,DM層主要是用泛型來解決問題,代碼如下:

public class DMbase
    {
        protected DbContext db;
        public DMbase(DbContext db)
        {
            this.db = db;
        }

        /// <summary>
        /// select one
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity">這里的entity並無實際作用,只是用於編譯器推敲類型</param>
        /// <param name="predicate">λ表達式</param>
        /// <returns>返回第一條匹配的記錄,若無記錄返回null</returns>
        public virtual T FindOne<T>(T entity, Func<T, bool> expression) 
            where T : class, new()
        {
            return this.db.Set<T>().FirstOrDefault(expression);
        }
        
        /// <summary>
        /// select all
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity">這里的entity並無實際作用,只是用於編譯器推敲類型</param>
        public virtual IQueryable<T> FindAll<T>(T entity) 
            where T : class, new()
        {
            return this.db.Set<T>();
        }

        public virtual void Insert<T>(params T[] entities)
            where T : class, new()
        {
            if (entities != null && entities.Length > 0)
            {
                var set = this.db.Set<T>();
                foreach (var item in entities)
                {
                    set.Add(item);
                }
            }
        }

        public virtual void Delete<T>(params T[] entities)
            where T : class, new()
        {
            if (entities != null && entities.Length > 0)
            {
                var set = this.db.Set<T>();
                foreach (var item in entities)
                {
                    set.Remove(item);
                }
            }
        }

        /// <summary>
        /// 提交事務
        /// </summary>
        public void Commit()
        {
            this.db.SaveChanges();
        }
    }

我的注釋也說明了,其實FindOne方法和FindAll方法其實是不需要參數的,但是為了編譯器推敲類型,傳入了一個entity參數

在此要感謝下xanthodont同學,這個DM是在你的版本上改的,封裝得很不錯

 

寫完DM層,接下來就是重頭戲,Service層

下面的代碼示范了如何取得所有的Teacher,並將Teacher與Contact對應起來

        public object FindAllTeacher()
        {
            //取得一個Context
            var context = ContextFactory.GetContext();

            //從Factory中取得Teacher和Contact
            //這里必須要用var
            var a = ModelFactory.GetTeacher();
            var b = ModelFactory.GetContact();
            var aList = ModelListFactory.GetTeacherList();

            DMbase dm = new DMbase(context);

            //用之前取得的Teacher與Contact傳入DM層,方便編譯器推敲類型
            var contact = dm.FindAll(b);
            var teacher = dm.FindAll(a);

            //業務邏輯,將Teacher與Contact關聯起來
            var result = teacher.Join(contact, o => o.ID, r => r.TeacherID, (o, r) => new { tt = o, aa = r });
            result = result.OrderByDescending(o => o.aa.Email);

            //處理數據
            foreach (var item in result)
            {
                a = item.tt;
                a.Contact = item.aa;
                aList.Add(a);
            }
            return aList;
        }

 

 

注意,這里我使用了Object作為返回類型,因為我其實不知道返回值是IList<Model.A.Teacher> 還是IList<Model.B.Teacher>,好在這里只需要一次拆裝箱,無傷大雅

 

再來演示下如何插入:

        public bool AddTeacher<T, T1>(T teacher, T1 contact)
            where T : class,new()
            where T1 : class,new()
        {
            try
            {
                var context = ContextFactory.GetContext();
                DMbase dm = new DMbase(context);
                dm.Insert(teacher);
                dm.Insert(contact);
                dm.Commit();

                return true;
            }
            catch
            {
                return false;
            }
        }

 

只有執行了dm.Commit(),兩個Insert才會提交到數據庫,保證了事務的一致性

 

就此擱筆

 

PS:昨天是博主生日,又老了一歲;有緣讀到這里的園友,就別吝嗇自己的祝福了吧 :)

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM