领域模型设计

NHibernate实战详解(一)领域模型设计

关于NHibernate的资料本身就不多,中文的就更少了,好在有一些翻译文章含金量很高,另外NHibernate与Hibernate的使用方式可谓神似,所以也有不少经验可以去参考Hibernate。

 

本文是实战中的心得,也是NHibernate进阶教程,假设你已经看过NHibernate的文档,但对它还是觉得无法驾驭,那么你可以看看本文,或者你只是想看看其他人在实战中是如何使用它的,你也可以看看。

 

所以,本文提到的内容绝对是干货。

 

本文主要会涉及到这些概念,关键字:级联操作 多表查询 复杂查询 值对象

 

 

 

需求简述:

 

简单地描述一下,有一个批次,一个批次包含多个订单,每个订单又可以有3个任务步骤要处理。

 

有时候我们需要获取一个批次,然后对这个批次下所有订单进行处理,也可能会涉及到订单的任务(数据库中可能涉及到3张有关联的表);

 

有时候我们也会获取一个订单,然后看这个订单属于哪个批次,还有就是对这个订单的任务步骤进行操作;

 

有时候我们会有相对复杂的查询,比如说要显示到第二个任务步骤的订单,并且第一个任务步骤已经完成,然后还需要根据订单中的日期进行过滤;

 

 

 

业务规则:

 

一个批次可以有多个订单,订单号不能重复;

 

一个订单有3个任务步骤,而且是三种不同类型的任务步骤;

 

也就是说如果我们获取了一个批次对象,它可能包含了40个订单,每个订单最多有4种任务类型,但转换成数据库SQL查询语句可能会返回最多160条记录。

 

 

 

 

 

关注领域模型,以领域模型为中心

 

领域模型设计

 

图1-1 领域模型图

 

 

 

上图可以看出三个领域模型之间都存在着密切的关系。

 

 

 

批次类,批次被创建的时候(也就是new实例化的时候),它的创建时间(CreateDate)就是系统默认时间,

 

然后他有一个名字(Name),并且它依赖了一个集合(订单集合),和一些方法,一些操作订单的方法。

 

你会发现我这里使用的是Isei类库,大家都知道这个是表示这个集合不能重复的。

 

另外一些操作订单的方法里都会有一句“order.PurchaseTime = null;”或者"order.PurchaseTime = this;",

 

这表示我们在批次中添加订单的同时,让订单对象也关联到批次,让订单对象可以感知到批次的存在,这一点非常重要。

 

复制代码
public class PurchaseTime : DomainBase

{

        public PurchaseTime()

        {

            CreateDate = DateTime.Now;

            Status = "0";

            SalesmanStatus = "0";

            StorageStatus = "0";

        }



        /// </summary>

        public virtual string Name

        {

            get; 

            set; 

        }        







        private ICollection<PurchaseOrder> _purchaseOrders = new Iesi.Collections.Generic.HashedSet<PurchaseOrder>();

        public virtual ICollection<PurchaseOrder> PurchaseOrders

        {

            get

            {

                return _purchaseOrders;

            }

            set

            {

                _purchaseOrders = value;

            }

        }



        public virtual void ClearOrders()

        {

            foreach (PurchaseOrder order in this._purchaseOrders)

            {

                order.PurchaseTime = null;

            }

            this._purchaseOrders.Clear();

        }



        public virtual void AddOrder(PurchaseOrder order)

        {

            order.PurchaseTime = this;

            this._purchaseOrders.Add(order);

        }



        public virtual void RemoveOrder(PurchaseOrder order)

        {

            order.PurchaseTime = null;

            this._purchaseOrders.Remove(order);

        }

}
复制代码

 


订单类,这个订单的业务逻辑已经被我砍掉很多了,只保留一些我们要讨论的内容,本来它的内容相当丰富。

 

可以看到顶到依赖一个批次对象,并且可以拥有任务集合。

 

AppointTask方法里面包含了许多逻辑,首先会调用ContainsTask判断该订单是否已经有这个任务步骤,它只是执行这样一句“_purchaseTasks.Contains(task);”,

 

意思是看一下该订单的任务集合中是不是有相同的任务对象存在,这里非常有意思,通常比较两个对象是否相等.NET会从内存中去比较他们是不是同一个对象,而使用NHibernate的话我们可能会希望他们的ID属性是不是同一个来判断他们是否相等,所以我们一般会涉及一个所有领域模型的基类,来重写Equals和GetHashCode方法。

 

但是我们上面的需求提到验证任务类型存不存在,所以我们关心的不是ID相不相等,而是类型(takstype)相不相等,后面会提到如何重写Equals和GetHashCode方法。

 

这个领域模型的设计已经给后面的设计打下了重要的基础,为什么我们不写存储过程,或者是再查询一次数据库来验证是否存在或者什么的。

 

复制代码
public class PurchaseOrder : DomainBase

{

        /// <summary>

        /// 订单号

        /// </summary>

        public virtual string OrderNumber

        {

            get; 

            set; 

        }        



  



        /// <summary>

        /// 交货日期

        /// </summary>

        public virtual DateTime? DateOfDelivery

        {

            get; 

            set; 

        }        







        private PurchaseTime _purchaseTime = new PurchaseTime();



        public virtual PurchaseTime PurchaseTime

        {

            get

            {

                return _purchaseTime;

            }

            set

            {

                _purchaseTime = value;

            }

        }





        private ICollection<PurchaseTask> _purchaseTasks = new HashedSet<PurchaseTask>();

        public virtual ICollection<PurchaseTask> PurchaseTasks

        {

            get

            {

                return _purchaseTasks;

            }

             set

            {

                _purchaseTasks=value;

            }

        }



        /// <summary>

        /// 指派任务

        /// </summary>

        /// <param name="task"></param>

        public virtual void AppointTask(PurchaseTask task)

        {

            if (ContainsTask(task))

            {

                if (TaskProgress == 0)

                {

                    RemoveTask(task);

                }

                else

                {

                    throw new Exception("任务已经开始,无法重新指派!");

                }

            }

            if (task.Principal != 0)

            {

                task.PurchaseOrder = this;

                _purchaseTasks.Add(task);

            }

        }



        public virtual void ClearTask()

        {

            foreach (PurchaseTask item in _purchaseTasks)

            {

                item.PurchaseOrder = null; 

            }

            _purchaseTasks.Clear();

        }



        public virtual void RemoveTask(PurchaseTask task)

        {

            task.PurchaseOrder = null;

            _purchaseTasks.Remove(task);

        }



        public virtual bool ContainsTask(PurchaseTask task)

        {

            return _purchaseTasks.Contains(task);

        }



        /// <summary>

        /// 任务进度 

        /// 0未开始 

        /// 1完成

        /// 2完成 

        /// 3完成

        /// </summary>

        public virtual decimal? TaskProgress

        {

            get;

            set;

        }



}
复制代码

 


任务类,在这个类的最后我们已经看到override比较对象相等的方法了。

 

复制代码
public class PurchaseTask : DomainBase

{

        private PurchaseOrder _purchaseOrder = new PurchaseOrder();



        /// <summary>

        /// PurchaseOrder

        /// </summary>

        public virtual PurchaseOrder PurchaseOrder

        {

            get { return _purchaseOrder; }

            set {  _purchaseOrder=value; }

        }        

        /// <summary>

        /// 任务类型

        /// 类型1 类型2 类型3

        /// </summary>

        public virtual decimal? TaskType

        {

            get; 

            set; 

        }        

        /// <summary>

        /// 任务负责人ID

        /// </summary>

        public virtual decimal? Principal

        {

            get; 

            set; 

        }        



        /// <summary>

        /// 是否处理

        /// </summary>

        /// <returns></returns>

        public virtual bool IfHandle()

        {

            if (this.PurchaseOrder.TaskProgress ==GetNeedHandleProgress(this.TaskType))

            {

                return true;

            }

            return false;

        }





        /// <summary>

        /// 获取需要处理的进度步骤

        /// </summary>

        /// <param name="tasktype"></param>

        /// <returns></returns>

        public virtual decimal? GetNeedHandleProgress(decimal? tasktype)

        {

            switch (tasktype.ToString().ToLower())

            {

                case "1":

                    return 0;

                case "2":

                    return 2;

                case "3":

                    return 3;

                default:

                    throw new Exception("任务类型错误!无法定位需要处理的进度。");

            }

        }





        public override bool Equals(object obj)

        {

            PurchaseTask task = obj as PurchaseTask;

            if (task == null)

                return false;

            return TaskType.Equals(task.TaskType);

        }



        public override int GetHashCode()

        {

            return TaskType.GetHashCode();

        }           

}
复制代码

 

 

 

这一节就到这里,在下一节中将会看到映射文件(hbm.xml)的编写,与一些级联的操作(级联保存、多表查询)的应用。

 

 

 

 

 

分类:  架构设计

 

 
 

你可能感兴趣的:(领域驱动设计,NHibernate)