Abp vnext Web应用程序开发教程 6 —— 作者:领域层
文章目录
- 关于本教程
- 下载源代码
- 介绍
- 作者实体
- AuthorManager:领域服务
- IAuthorRepository
- 结论
- 下一部分
关于本教程
本教程基于版本3.1
在本教程系列中,您将构建一个名为Acme.BookStore
的基于ABP的Web应用程序。该应用程序用于管理书籍及其作者的列表。它是使用以下技术开发的:
- 实体框架核心作为ORM提供者。
- MVC/Razor页面作为UI框架。
本教程分为以下部分:
第1部分:创建服务器端
第2部分:书籍列表页面
第3部分:创建、更新和删除书籍
第4部分:集成测试
第5部分:授权
第6部分:作者:领域层(此部分)
第7部分:作者:数据库集成
第8部分:作者:应用程序层
第9部分:作者:用户界面
第10部分:书与作者的关系
下载源代码
MVC (Razor Pages) UI with EF Core
介绍
在前面的部分中,我们使用了ABP基础结构轻松构建了一些服务。
使用CrudAppService基类,而不是为标准的创建,读取,更新和删除操作手动开发应用程序服务。
使用通用存储库来完全自动化数据库层。
对于“作者”部分;
我们将手动执行某些操作,以显示在需要时如何执行此操作。
我们将实现一些域驱动设计(DDD)最佳实践。
开发将逐层完成,以一次集中在一个单独的层上。在真实的项目中,您将按照前面各部分的功能(垂直)来开发应用程序功能。这样,您将体验两种方法。
作者实体
在Acme.BookStore.Domain
项目中创建一个Authors
文件夹(名称空间),并在其中添加一个Author
类:
using System;
using JetBrains.Annotations;
using Volo.Abp;
using Volo.Abp.Domain.Entities.Auditing;namespace Acme.BookStore.Authors
{public class Author : FullAuditedAggregateRoot<Guid>{public string Name { get; private set; }public DateTime BirthDate { get; set; }public string ShortBio { get; set; }private Author(){/* This constructor is for deserialization / ORM purpose */}internal Author(Guid id,[NotNull] string name,DateTime birthDate,[CanBeNull] string shortBio = null): base(id){SetName(name);BirthDate = birthDate;ShortBio = shortBio;}internal Author ChangeName([NotNull] string name){SetName(name);return this;}private void SetName([NotNull] string name){Name = Check.NotNullOrWhiteSpace(name, nameof(name), maxLength: AuthorConsts.MaxNameLength);}}
}
继承自
FullAuditedAggregateRoot<Guid>
,可以对实体进行软删除(这意味着在删除它时,它不会在数据库中删除,而只是标记为已删除),并具有所有的审计属性。对于
Name
属性的private set
限制从此类之外设置此属性。有两种设置名称的方法(在两种情况下,我们都会验证名称):- 在构造函数中,同时创建一个新作者。
- 稍后使用
ChangeName
方法来更新名称。
constructor
和ChangeName
方法是internal
迫使仅在领域层使用这些方法,使用AuthorManager
将在后面说明。Check
类是ABP Framework实用程序类,可在检查方法参数时提供帮助(在无效的情况下它会抛出ArgumentException
异常)。
AuthorConsts
是一个简单的类,位于Acme.BookStore.Domain.Shared
项目的Authors
名称空间(文件夹)下:
namespace Acme.BookStore.Authors
{public static class AuthorConsts{public const int MaxNameLength = 64;}
}
在Acme.BookStore.Domain.Shared
项目内部创建了此类,因为稍后我们将在数据传输对象(DTO)上重用该类。
AuthorManager:领域服务
Author
构造函数和ChangeName
方法是internal
的,因此它们只能在领域层中使用。在Acme.BookStore.Domain
项目的Authors
文件夹(名称空间)中创建一个AuthorManager
类:
using System;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Volo.Abp;
using Volo.Abp.Domain.Services;namespace Acme.BookStore.Authors
{public class AuthorManager : DomainService{private readonly IAuthorRepository _authorRepository;public AuthorManager(IAuthorRepository authorRepository){_authorRepository = authorRepository;}public async Task<Author> CreateAsync([NotNull] string name,DateTime birthDate,[CanBeNull] string shortBio = null){Check.NotNullOrWhiteSpace(name, nameof(name));var existingAuthor = await _authorRepository.FindByNameAsync(name);if (existingAuthor != null){throw new AuthorAlreadyExistsException(name);}return new Author(GuidGenerator.Create(),name,birthDate,shortBio);}public async Task ChangeNameAsync([NotNull] Author author,[NotNull] string newName){Check.NotNull(author, nameof(author));Check.NotNullOrWhiteSpace(newName, nameof(newName));var existingAuthor = await _authorRepository.FindByNameAsync(newName);if (existingAuthor != null && existingAuthor.Id != author.Id){throw new AuthorAlreadyExistsException(newName);}author.ChangeName(newName);}}
}
AuthorManager
强制创建作者并以受控方式更改作者的姓名。应用程序层(稍后将介绍)将使用这些方法。
DDD技巧:除非确实需要领域服务方法并执行一些核心业务规则,否则请不要引入领域服务方法。对于这种情况,我们需要此服务能够强制唯一名称约束。
两种方法都会检查是否存在具有给定名称的作者,并引发在Acme.BookStore.Domain
项目(在Authors
文件夹中)中定义的特殊业务异常AuthorAlreadyExistsException
,如下所示:
using Volo.Abp;namespace Acme.BookStore.Authors
{public class AuthorAlreadyExistsException : BusinessException{public AuthorAlreadyExistsException(string name): base(BookStoreDomainErrorCodes.AuthorAlreadyExists){WithData("name", name);}}
}
BusinessException
是一种特殊的异常类型。在需要时抛出与领域相关的异常是一个好习惯。它由ABP框架自动处理,并且可以轻松地进行本地化。WithData(...)
方法用于向异常对象提供其他数据,这些数据以后将在本地化消息上使用或用于某些其他目的。
在Acme.BookStore.Domain.Shared
项目中打开BookStoreDomainErrorCodes
并进行如下更改:
namespace Acme.BookStore
{public static class BookStoreDomainErrorCodes{public const string AuthorAlreadyExists = "BookStore:00001";}
}
这是一个唯一的字符串,表示您的应用程序引发的错误代码,并且可以由客户端应用程序处理。对于用户,您可能想对其进行本地化。打开Acme.BookStore.Domain.Shared
项目内部的Localization/BookStore/en.json
,并添加以下条目:
"BookStore:00001": "There is already an author with the same name: {name}"
然后打开BookStoreDomainSharedModule
并在ConfigureServices
方法内添加以下代码块:
Configure<AbpExceptionLocalizationOptions>(options =>
{options.MapCodeNamespace("BookStore", typeof(BookStoreResource));
});
每当您抛出AuthorAlreadyExistsException
时,最终用户将在UI上看到一条不错的错误消息。
IAuthorRepository
AuthorManager
注入IAuthorRepository
,因此我们需要对其进行定义。在Acme.BookStore.Domain
项目的Authors
文件夹(名称空间)中创建此新接口:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;namespace Acme.BookStore.Authors
{public interface IAuthorRepository : IRepository<Author, Guid>{Task<Author> FindByNameAsync(string name);Task<List<Author>> GetListAsync(int skipCount,int maxResultCount,string sorting,string filter = null);}
}
IAuthorRepository
扩展了标准IRepository<Author, Guid>
接口,因此IAuthorRepository
也可以使用所有标准存储库方法。FindByNameAsync
在AuthorManager
中用于按名称查询作者。GetListAsync
将在应用程序层中使用,以获取列出的,经过排序和筛选的作者列表,以显示在UI上。
我们将在下一部分中实现此存储库。
这两种方法似乎都没有必要,因为标准存储库已经具有
IQueryable
并且可以直接使用它们,而不是定义这样的自定义方法。你是对的,就像在一个真实的应用程序中一样。但是,对于本学习教程,解释在真正需要时如何创建自定义存储库方法是很有用的。
结论
这部分涵盖了书店应用程序作者功能的领域层。下图突出显示了在此部分中创建/更新的主要文件:
下一部分
请参阅本教程的下一部分。
Abp vnext Web应用程序开发教程 6 —— 作者:领域层相关推荐
- Abp vnext Web应用程序开发教程 9 —— 作者:用户界面
文章目录 关于本教程 下载源代码 介绍 图书列表页面 Index.cshtml IndexModel.cshtml.cs Index.js 本地化 添加到主菜单 运行应用程序 创建模态 CreateM ...
- Abp vnext Web应用程序开发教程 8 —— 作者:应用程序层
文章目录 关于本教程 下载源代码 介绍 IAuthorAppService AuthorDto GetAuthorListDto CreateAuthorDto UpdateAuthorDto Aut ...
- Abp vnext Web应用程序开发教程 7 —— 作者:数据库集成
文章目录 关于本教程 下载源代码 介绍 数据库上下文 创建一个新的数据库迁移 实现IAuthorRepository 下一部分 关于本教程 本教程基于版本3.1 在本教程系列中,您将构建一个名为Acm ...
- Abp vnext Web应用程序开发教程 10 —— 书与作者的关系
文章目录 关于本教程 下载源代码 介绍 向书实体添加关系 数据库和数据迁移 更新EF核心映射 添加新的EF核心迁移 更改数据播种器 应用层 数据传输对象 IBookAppService BookApp ...
- Abp vnext Web应用程序开发教程 4 —— 集成测试
文章目录 关于本教程 下载源代码 在解决方案中测试项目 添加测试数据 测试BookAppService 下一部分 关于本教程 本教程基于版本3.1 在本教程系列中,您将构建一个名为Acme.BookS ...
- Abp vnext Web应用程序开发教程 3 —— 创建、更新和删除书籍
文章目录 关于本教程 下载源代码 创建新书 创建模态表单 添加"新书"按钮 更新书 EditModal.cshtml.cs 从BookDto映射到CreateUpdateBookD ...
- Abp vnext Web应用程序开发教程 1 —— 创建服务器端
文章目录 关于本教程 下载源代码 创建解决方案 创建书籍实体 BookType枚举 将图书实体添加到DbContext 将图书实体映射到数据库表 添加数据库迁移 添加样本种子数据 更新数据库 创建应用 ...
- Abp vnext Web应用程序开发教程 2 —— 图书列表页面
文章目录 关于本教程 下载源代码 动态JavaScript代理 在开发者控制台中进行测试 本地化 创建书籍页面 将书籍页面添加到主菜单 图书列表 运行最终应用程序 下一部分 关于本教程 本教程基于版本 ...
- Abp vnext Web应用程序开发教程 5 —— 授权
文章目录 关于本教程 下载源代码 权限 权限名称 权限定义 权限管理界面 授权 应用层和HTTP API Razor页面 JavaScript端 菜单项 下一部分 关于本教程 本教程基于版本3.1 在 ...
最新文章
- pytorch nn.Conv2d
- mqtt服务器性能H3,运用 MQTT-JMeter 插件测试 MQTT 服务器性能
- Android TextView 高亮字体并添加点击事件
- ExtJs ComboBox 在IE 下 自动完成功能无效的解决方案
- 积极打破消极思维模式
- 艾创机器人_世界教育机器人大赛 2019赛季世界锦标赛落幕曲靖代表队获多个奖项...
- CSS Expression用法总结
- 结构型模式概述(Structural Pattern)
- 分布式存储中HDFS与Ceph两者的区别是什么,各有什么优势?
- 验证列数据是否重复方法归类贴
- python建模与仿真控制系统_控制系统的建模与仿真
- 多加速器驱动AGX的目标检测与车道分割
- 一维的热传导方程向前差分法
- WINRAR诊断信息:不可预料的压缩文件末端
- 粗糙集(Rough Sets)
- python 读取zip包中的数据
- 校园网路由器有线中继(针对802.1X)
- nextcloud19.0.1部署
- STM32F407系统标准库函数之时钟配置 和 位带操作
- C语言中的空指针、空指针常量、NULL 0
热门文章
- 测速源码_解密,相亲交友直播系统源码,高并发如何做到不卡顿
- 中关村企业 大数据_中关村大数据产业联盟秘书长赵国栋:数字经济区别于传统经济 是企业转型升级的顶层战略...
- 中国红+金牛|传统农历年新年新春海报稳妥设计方案!
- 火热抢购(双11)双12通用海报设计素材,PSD分层!
- 最新创意购物促销海报设计,广告人必看!
- 电商促销活动那么多,美工需要炫酷海报万能模板!可套用!救急必备!
- 建议把英语改成选修的计算机老师,中小学“变动”,英语改为副科?老师没意见家长却愁眉不展...
- ansys 内聚力模型_《ANSYS Workbench有限元分析实例详解(静力学)》,9787115446312
- 利用ptrace和memfd_create混淆程序名和参数
- FD.io VSAP(VPP Stack Acceleration Project),通过FD.io VSAP构建用户态协议栈