《ASP.NET Core技术内幕与项目实战》精简集-DDD准备5.2:贫血模型和充血模型
本节内容,部分为补充内容,部分涉及到99.3(P311-320)。主要NuGet包:无
领域建模有两种方式,一是贫血模式,二是充血模型。EFCore对充血模型,已经有了非常好的支持,我们应该通过充血模型的方式来设计实体,将有关个体的业务逻辑封装在实体内。
一、贫血模型:又叫POCO类,类中只有属性或成员变量,没有方法。
1、贫血模型实体类UserAnemic
public class UserAnemic {
public string? UserName { get; set; } public string? Password { get; set; } public int Credit { get; set; } }
2、实现以下几个业务逻辑:①UserAnemic对象必须有名称;②初始积分为10;③判断密码是否正常;④如果登陆成功,积分加5分;如果登陆失败,积分减3分,但如果不够减,则提示积分不足。这些业务逻辑,都属于个体行为,但都暴露在类的外面,且约束力不强,如对象的姓名,很可能会忘记赋值,初始积分,也可能出错。
UserAnemic u1 = new UserAnemic(); u1.UserName = "Test"; u1.Credit = 10; u1.Password ="123456"; string pwd = Console.ReadLine(); if (pwd == u1.Password) { u1.Credit += 5; Console.WriteLine("登陆成功"); } else { if (u1.Credit < 3) { Console.WriteLine("积分不足,无法扣减"); } else { u1.Credit -= 3; Console.WriteLine("登陆失败"); } Console.WriteLine("登陆失败"); }
二、充血模型:类中即有属性、成员变量,也有方法。属于个体的行为,封装在类中,体现“单一职责原则”。当应用中其它地方需要使用这个类时,让使用者无须关心类的内部实现,直接复用类的业务逻辑即可。同时,也体现了业务驱动设计,如下例中的设置密码、检查密码、增加积分、减少积分,业务、产品、开发等各环节沟通的语言均是这些业务逻辑,而不是具体的技术细节。
public class UserRich { //姓名只可以在对象初始化时设置 public string UserName { get; init; } //积分只可以在类的内部修改 public int Credit { get; private set; } //密码外部不可以直接修改 private string? password; //对象初始化,姓名必填,积分初始化为10分 public UserRich(string name) { this.UserName = name; this.Credit = 10; } //设置密码逻辑 public void SetPassword(string password) { if (password.Length<6) { throw new ArgumentException("密码太短了!"); } this.password = password; } //检查密码逻辑 public bool CheckPassword(string password) { return this.password == password; } //减少积分逻辑 public void DeductCredit(int credit) { if (credit<=0) { throw new ArgumentException("额度不能为负值"); } this.Credit -= credit; } //增加积分逻辑 public void AddCredit(int credit) { this.Credit += credit; } }
2、实现业务逻辑
UserRich u1 = new UserRich("functionMC"); u1.SetPassword("123456"); string pwd = Console.ReadLine(); if (u1.CheckPassword(pwd)) { u1.AddCredit(5); Console.WriteLine("登陆成功"); } else { u1.DeductCredit(3); Console.WriteLine("登陆失败"); }
三、EFCore对充血模型的支持:EFCore对充血模型的支持非常好,下例中,列举了EFCore对充血模型的七项支持。
1、充血模型案例 /充血模型User实体类,User.cs
public class User { public int Id { get; init; } //EFCore支持①只能在初始化时赋值,Id属性由数据库自动赋值 public DateTime CreatedDateTime { get; init; } //EFCore支持①只能在初始化时赋值 public string UserName { get; private set; } //EFCore支持②只能在类内部修改 public int Credit { get; private set; } //EFCore支持②只能在类内部修改 private string? password; //EFCore支持③私有成员,不能被外部访问,没有对应属性,但需要映射到数据库,在DbContext中设置 private string? remark; public string? Remark { get; } //EFCore支持④只读属性,只能从数据库中读出值,但不能修改值 public string? Tag { get; set; } //EFCore支持⑤不需要映射到数据库,在DbContext中设置 private User() //EFCore支持⑥私有无参构造函数,一方面外部无法调用、防止空对象;另一方面,EFCore默认调用,将各个属性与数据库映射 { } public User(string name) //EFCore支持⑦公共有参构造函数,外部调用这个构造函数进行对象的初始化 { this.UserName = name; this.CreatedDateTime = DateTime.Now; this.Credit = 10; } //EFCore支持②只能在类内部修改,外部调用方法修改姓名 public void ChangeUserName(string newName) { this.UserName = newName; } //EFCore支持③私有成员,不能被外部访问,没有对应属性,但需要映射到数据库,在DbContext中设置 public void ChangePassword(string newPassword) { if (newPassword.Length<6) { throw new ArgumentException("密码长度不能低于6位"); } this.password = newPassword; } } //DbContext设置MyDbContext.cs public class MyDbContext:DbContext { public DbSet<User> Users { get; set; } ...... protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<User>(b => { b.ToTable("T_Users");
//EFCore支持③私有成员映射到数据库,UsePropertyAccessMode设置访问模式
b.Property<string>("password").UsePropertyAccessMode(PropertyAccessMode.Field).HasColumnName("Password"); b.Property(u => u.Remark).HasField("remark"); //EFCore支持④只读属性映射 b.Ignore(u=>u.Tag); //EFCore支持⑤不映射到数据库 }); } }
2、测试代码和结果
using var ctx = new MyDbContext(); //User u1 = new User("functionMC"); //u1.Tag = "TestTag"; //u1.ChangePassword("123456"); //ctx.Users.Add(u1); //ctx.SaveChanges(); var u1 = ctx.Users.FirstOrDefault(); Console.WriteLine(u1); //如要直接打印对象的字符串,将User类改为record。 打印结果: ============================================================================================================ User { Id = 1, CreatedDateTime = 2022/11/25 16:52:14, UserName = functionMC, Credit = 10, Remark = , Tag = }
特别说明:
1、本系列内容主要基于杨中科老师的书籍《ASP.NET Core技术内幕与项目实战》及配套的B站视频视频教程,同时会增加极少部分的小知识点
2、本系列教程主要目的是提炼知识点,追求快准狠,以求快速复习,如果说书籍学习的效率是视频的2倍,那么“简读系列”应该做到再快3-5倍
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!