浅谈C#中的延迟加载(3)——还原“.NET研究”模型的业务规则

简介:   上一篇文章讲到把实体类中需要实现延迟加载的属性声明为virtual,然后继承实体类做一个子类,在子类里面实现该属性,配合使用委托来实现比较完美的延迟加载(原本的模型层依旧保持在最底层用于贯穿三层结构,同时又可以上海企业网站制作实现在实体类的属性里面访问到比他高层的数据访问层)。

  上一篇文章讲到把实体类中需要实现延迟加载的属性声明为virtual,然后继承实体类做一个子类,在子类里面实现该属性,配合使用委托来实现比较完美的延迟加载(原本的模型层依旧保持在最底层用于贯穿三层结构,同时又可以上海企业网站制作实现在实体类的属性里面访问到比他高层的数据访问层)。文章的最后依旧出现杯具,原因是在对模型的属性实现延迟加载之前,这个属性可能由于我们业务的需要,它并不单单是作为一个存储和读取的功能使用,而是在其get或者set的访问器中都包含这或许复杂或许简单的逻辑代码。

  举例:考虑一下这个情景,我们有一个叫做任务单的实体类,其中有两个属性,一个叫做任务名,一个叫做发布时间,现在有这样的业务规定,任务名称可以为空,但如果任务名称为空的话我们要读取发布时间生成一个任务名来代替掉这个空值(例如叫做Issue20110120191345),当然这个例子有点牵强,主要是我想不出什么很具体的实例,但是在实际开发中这种情况肯定是有的并且其中的逻辑代码有可能复杂到你难以想象。

  沿用前面两篇文章的例子,我模拟了这一现象,对文章实体类做了点修改,增加了一个名为GetCategoryRecord的字符串型属性,它的作用基本上可以从字面上看出来,叫做Category属性get访问器调用记录。于是文章类(基类)修改如下:

 
 
c#代码

namespace Model
{
// 文章实体类
public class Article
{
public int A上海徐汇企业网站设计与制作rticleID { get ; set ; }
public string Title { get ; 上海闵行企业网站制作an style="color: #0000ff;">set ; }
public string Cotnent{ get ; set ; }
public DateTime CreateTime { get ; set ; }
public int CategoryID { get ; set ; }
/// <summary>
/// 所属分类
/// </summary>
protected Model.ArticleCategory _category;
/// <summary>
/// 所属分类
/// </summary>
public virtual Model.ArticleCategory Category
{
get
{
GetCategoryRecord
+= " 获取分类; " ;
return _category;
}
}
/// <summary>
/// Category属性get访问器调用记录
/// </summary>
public string GetCategoryRecord { get ; set ; }
}
}

  这里我们关心那两个有写注释的属性,并且出现了一个保护字段_category(这个尤其重要,起到和子类的联通作用)。可以看到现在有这样的业务规则了:Category属性被get一次就会往GetCategoryRecord属性中做点记录。于是我们在设计代码的时候立刻会想到要是继承Model.Article类的基类要是重写这个属性的话势必要保持这个业务不变,否则在实现延迟加载之后肯定会丢掉一些之前设计好的业务逻辑了。修改继承它的子类如下:

 
 
c#代码

namespace DModel
{
/// <summary>
/// 文章
/// </summary>
public class Article : Model.Article
{
/// <summary>
/// 所属分类
/// </summary>
public override Model.ArticleCategory Category
{
get
{
if ( base ._category == null )
{
if (CategoryLazyLoader != 上海企业网站设计与制作le="color: #000000;"> null )
{
base ._category = CategoryLazyLoader(CategoryID);
}
else
{
base ._category = null ;
}
}
return base .Category;
}
}
/// <summary>
/// 文章分类延时加载器(委托)
/// </summary>
public Func < int , Model.ArticleCategory > CategoryLazyLoader { get ; set ; }
}
}

  这里可以看到DModel.Article类的Category属性中对基类的保护字段base._cateogry进行了操作,最后返回的是基类Category。粗看起来似乎有点乱,但是理清一下思路其实如下:基类的Category属性通过返回_category字段的方式返回值,也就是说数据是存在_category字段而不是属性中,但是_category字段怎么才会有值呢,那就是在子类里面通过调用委托拿来的,而这个属性在子类里面不是直接返回的,而是调用基类来返回,这样一来,调用到子类的Category属性的get访问器的时候,先对基类的_categoty字段赋值,然后调用基类的Category属性执行了一些逻辑代码,最后成功地把(已经被赋值的)基类的_categoty字段给返回去。而这一切都是在前面我们实现好的延迟加载的基础上完成的。总结成几个字就是:子类负责延时加载,基类赋值数据存储和返回!呵呵,是不是觉得很简单呢。

这里可以看到DModel.Article类的Category属性中对基类的保护字段base._cateogry进行了操作,最后返回的是基类Category。粗看起来似乎有点乱,但是理清一下思路其实如下:
基类的Category属性通过返回_category字段的方式返回值,也就是说数据是存在_category字段而不是属性中,但是_category字段怎么才会有值呢,那就是在子类
里面通过调用委托拿来的,而这个属性在子类里面不是直接返回的,而是调用基类来返回,这样一来,调用到子类的Category属性的get访问器的时候,先对_categoty字段赋值,然后调用基类的Category属性实现了一些逻辑代码,最后成功地把(已经被赋值的)_categoty字段给返回去。而这一切都是在前面我们实现好的延迟加载的基础上完成的。呵呵,是不是觉得很简单呢^^
这里可以看到DModel.Article类的Category属性中 上海网站建设对基类的保护字段base._cateogry进行了操作,最后返回的是基类Category。粗看起来似乎有点乱,但是理清一下思路其实如下:
基类的Category属性通过返回_category字段的方式返回值,也就是说数据是存在_category字段而不是属性中,但是_category字段怎么才会有值呢,那就是在子类
里面通过调用委托拿来的,而这个属性在子类里面不是直接返回的,而是调用基类来返回,这样一来,调用到子类的Category属性的get访问器的时候,先对_categoty字段赋值,然后调用基类的Category属性实现了一些逻辑代码,最后成功地把(已经被赋值的)_categoty字段给返回去。而这一切都是在前面我们实现好的延迟加载的基础上完成的。呵呵,是不是觉得很简单呢^^

  其实这一篇讲的情况不是针对延迟加载这个技术来讲的,在我们的开发过程中经常会遇到这种实现了业务代码的实体类属性,拥有这种属性的模型通常被叫做充血模型,如果模型的属性都是简单的get和set的话通常叫做贫血模型(当然可能有其他叫法 哈~)。这篇文章是在没啥内容,算是对前两篇文章的一个补充吧,希望没有浪费你的时间哈^_^。

目录
相关文章
|
17天前
|
数据可视化
R语言弹性网络Elastic Net正则化惩罚回归模型交叉验证可视化
R语言弹性网络Elastic Net正则化惩罚回归模型交叉验证可视化
|
17天前
|
机器学习/深度学习 存储 计算机视觉
r语言中对LASSO回归,Ridge岭回归和弹性网络Elastic Net模型实现-4
r语言中对LASSO回归,Ridge岭回归和弹性网络Elastic Net模型实现
|
17天前
|
开发框架 .NET 中间件
C#/.NET快速上手学习资料集(让现在的自己不再迷茫)
C#/.NET快速上手学习资料集(让现在的自己不再迷茫)
|
4天前
|
开发框架 .NET C#
使用C#进行.NET框架开发:深入探索与实战
【5月更文挑战第28天】本文探讨了C#在.NET框架中的应用,展示了其作为强大编程语言的特性,如类型安全、面向对象编程。C#与.NET框架的结合,提供了一站式的开发环境,支持跨平台应用。文中介绍了C#的基础知识,如数据类型、控制结构和面向对象编程,以及.NET的关键技术,包括LINQ、ASP.NET和WPF。通过一个实战案例,展示了如何使用C#和ASP.NET开发Web应用,包括项目创建、数据库设计、模型和控制器编写,以及视图和路由配置。本文旨在揭示C#在.NET开发中的深度和广度,激发开发者探索更多可能性。
|
6天前
|
编译器 C#
C#.Net筑基-类型系统②常见类型 --record是什么类型?
`record`在C#中是一种创建简单、只读数据结构的方式,常用于轻量级数据传输。它本质上是类(默认)或结构体的快捷形式,包含自动生成的属性、`Equals`、`ToString`、解构赋值等方法。记录类型可以继承其他record或接口,但不继承普通类。支持使用`with`语句创建副本。例如,`public record User(string Name, int Age)`会被编译为包含属性、相等比较和`ToString()`等方法的类。记录类型提供了解构赋值和自定义实现,如密封的`sealed`记录,防止子类重写。
|
6天前
|
存储 安全 Unix
C#.Net筑基-类型系统②常见类型--日期和时间的故事
在System命名空间中,有几种表示日期时间的不可变结构体(Struct):DateTime、DateTimeOffset、TimeSpan、DateOnly和TimeOnly。DateTime包含当前本地或UTC时间,以及最小和最大值;DateTimeOffset增加了时区偏移信息,适合跨时区操作。UTC是世界标准时间,而格林尼治标准时间(GMT)不稳定,已被更精确的UTC取代。DateTimeOffset和DateTime提供了转换为UTC和本地时间的方法,以及各种解析和格式化函数。
|
6天前
|
安全 API C#
C#.Net筑基-类型系统②常见类型--枚举Enum
枚举(enum)是C#中的一种值类型,用于创建一组命名的整数常量。它们基于整数类型(如int、byte等),默认为int。枚举成员可指定值,未指定则从0开始自动递增。默认值为0。枚举可以与整数类型互相转换,并可通过`[Flags]`特性表示位域,支持位操作,用于多选场景。`System.Enum`类提供了如`HasFlag`、`GetName`等方法进行枚举操作。
|
6天前
|
存储 C#
C#.Net筑基-类型系统②常见类型--结构体类型Struct
本文介绍了C#中的结构体(struct)是一种用户自定义的值类型,适用于定义简单数据结构。结构体可以有构造函数,能定义字段、属性和方法,但不能有终结器或继承其他类。它们在栈上分配,参数传递为值传递,但在类成员或包含引用类型字段时例外。文章还提到了`readonly struct`和`ref struct`,前者要求所有字段为只读,后者强制结构体存储在栈上,适用于高性能场景,如Span和ReadOnlySpan。
|
17天前
|
XML 开发框架 .NET
C#/ASP.NET应用程序配置文件app.config/web.config的增、删、改操作
C#/ASP.NET应用程序配置文件app.config/web.config的增、删、改操作
21 1
|
17天前
|
机器学习/深度学习 算法 数据可视化
MATLAB基于深度学习U-net神经网络模型的能谱CT的基物质分解技术研究
MATLAB基于深度学习U-net神经网络模型的能谱CT的基物质分解技术研究