一步一步搭架子(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:昨天是博主生日,又老了一岁;有缘读到这里的园友,就别吝啬自己的祝福了吧 :)

 

 

 

你可能感兴趣的:(service)