打造可持续发展的事业

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

领域模型中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   PM2004  阅读(1288)  评论(8编辑  收藏  举报

编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
< 2009年11月 >
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 1 2 3 4 5
6 7 8 9 10 11 12

导航

统计

点击右上角即可分享
微信分享提示