打造可持续发展的事业

事业像系统的框架,要稳定、可扩展,同样需要精心设计的!

领域模型中Relationship的编码实现

问题引入

在尝试利用DDD(领域模型驱动开发)的思想来开发新的系统。由于领域模型思考的出发点是按照现实的业务实体来建立,得到一个更接近客观尽量稳定的模型。常常遇到对象之间关系,最常见的就是1n的关系,比如班级和学生的关系:

 

 

在实际设计编码中,对于有关系的2个类如何处理他们的关系呢?

1)双向导航?初始化存在麻烦。

2)单边导航?另外方向的查找会比较麻烦。

 

很容易得到他们的代码

public class CClase

{

         public string Name{get;set;}

         public ILazyList<CStudent> students{get;set}

        

}

public class CStudent

{

         public CClase MyClass{get;set;}

         public string Name{get;set;}

        

}

 

ILazyList<CStudent>将会延迟加载。其实在这个业务模型中,类中的字段应该都是必须的字段,在初始化时应该都能够确定。

 

 

在定义构造函数时,有下列几种方式:

理想模式:

CClase(string name,IQueryable<CStudent> stus);

CStudent(int id,string name,CClase c);

 

Service Layer或者Repository层有类似下面的代码:

public IQueryable<CClass> GetAllClasses()

{

         return from a in _db.Classes select new CClass(a.Name,from b in _db.Students where b.MyClass.Name==a.Name select new CStudent(b.Name,???));

}

???的代码将无法完成。陷入先有鸡还是先有蛋的困境。

 

折中模式:

一个折中的方案是:

public class CStudent

{

         privade string _className;

         public CClass MyClass{get{return _Service.GetClassByName(_className);}};

         public string Name{get;set;}  

         public CStudent(string name,string className)

         {

         Name=name;_className=className

         }

}

在服务层的代码将如下:

public IQueryable<CClass> GetAllClasses()

{

         return from a in _db.Classes select new CClass(a.Name,from b in _db.Students where b.MyClass.Name==a.Name select new CStudent(b.Name,a.Name));

}

这样带来的一个问题是领域模型这个层需要了解_Service这个层次,形成依赖。不够干净(不够贫血)

 

还有一个方案是:

在服务层的代码将如下:

public IQueryable<CClass> GetAllClasses()

{

         IQueryable<CClass> classes=from a in _db.Classes select new CClass(a.Name,from b in _db.Students where b.MyClass.Name==a.Name select new CStudent(b.Name,a.Name));

//循环给CStudent中的MyClass赋值,

Return classes;

}

由于循环了classes,这样需要真正执行SQL语句,这样将失去了延迟加载的好处了。

 

最终的方案:

//-------CStudent.cs---------------------

public class CStudent

{

         privade string _className;

         public string Name{get;set;}  

         public CStudent(string name,string className)

         {

                  Name=name;_className=className

         }

}

//---------ClassService.cs-----------------

public class ClassService

{

         MyDBContext _db;

         public ClassService(MyDBContext dbcotext)

{

         _db= dbcotext;

}

         public IQueryable<CClass> GetAllClasses()

{

                  return       from a in _db.Classes

let s= GetStudentsByClassName(a.Name)

                                    select new CClass(a.Name,s);

}

public IQueryable<CStudent> GetStudentsByClassName(string name)

{

         return       from b in _db.Students

where b.MyClass.Name==name

select new CStudent(b.Name,name);

}

public CClass GetClassByName(string name)

{

         return     from a in GetAllClasses().

                            where(x=>x.Name==name).

                            SingleOrDefault();

}

}

 

如果需要取得某个学生的班级请在使用层调用_Service.GetClassByName(_className)来取得。

也就是说只有单边的直接导航,另一侧采用间接导航。

 

posted on 2009-11-23 18:24  PM2004  阅读(1286)  评论(8编辑  收藏  举报

导航