创建业务用户
\n\n区别于身份管理模块(Identity模块)的鉴权用户IdentityUser,业务用户(BusinessUser)是围绕业务系统中“用户”这一定义的领域模型。如:在一个医院系统中,业务用户可以是医生、护士、患者;在一个OA系统中,业务用户可以是员工、管理员、客户等。
\n\n业务用户和鉴权用户由同步机制关联,业务用户通过分布式事件(DistributedEvent)的同步器(Synchronizer)与鉴权用户关联同步。
\n\n在Health业务模块中,定义两种业务用户:
\n\nClient: 客户;
\n\nEmployee: 员工。
\n\n这些业务用户继承自HealthUser,HealthUser是业务用户的基类,包含了业务用户的基本信息,如姓名,性别,出生日期,身份证号等。并且需要实现IUpdateUserData接口,以便在同步鉴权用户信息时,更新业务用户的基本信息。
\n\nEmployee包含工号,职称,简介等信息。其领域模型定义如下:
\n\n\npublic class Employee : HealthUser<Guid>, IUser, IUpdateUserData\n{\n [StringLength(12)]\n public string EmployeeNumber { get; set; }\n\n [StringLength(64)]\n public string EmployeeTitle { get; set; }\n\n public string Introduction { get; set; }\n\n ...\n}\n\n
\n\n
Client包含客户号,身高,体重,婚姻状况等信息。其领域模型定义如下:
\n\n\npublic class Client : HealthUser<Guid>, IUser, IUpdateUserData\n{\n\n //unique\n\n [StringLength(12)]\n public string ClientNumber { get; set; }\n\n public string ClientNumberType { get; set; }\n\n [Range(0.0, 250.0)]\n public double? Height { get; set; }\n\n\n [Range(0.0, 1000.0)]\n public double? Weight { get; set; }\n\n public string Marriage { get; set; }\n\n public string Status { get; set; }\n}\n\n
\n\n
创建业务用户同步器
\n\n以Client为例,ClientLookupService是业务用户的查询服务,其基类UserLookupService定义了关联用户的查询接口,包括按ID查询,按用户名查询,按组织架构查询,按户关系查询等。
\n\n创建ClientLookupService, 代码如下
\n\n\npublic class ClientLookupService : UserLookupService<Client, IClientRepository>, IClientLookupService\n{\n public ClientLookupService(\n IClientRepository userRepository,\n IUnitOfWorkManager unitOfWorkManager)\n : base(\n userRepository,\n unitOfWorkManager)\n {\n\n }\n\n protected override Client CreateUser(IUserData externalUser)\n {\n return new Client(externalUser);\n }\n}\n\n
\n\n
同步器订阅了分布式事件EntityUpdatedEto,当鉴权用户更新时,同步器将更新业务用户的基本信息。
\n\n创建ClientSynchronizer,代码如下
\n\n\npublic class ClientSynchronizer :\n IDistributedEventHandler<EntityUpdatedEto<UserEto>>,\n ITransientDependency\n{\n protected IClientRepository UserRepository { get; }\n protected IClientLookupService UserLookupService { get; }\n\n public ClientSynchronizer(\n IClientRepository userRepository,\n IClientLookupService userLookupService)\n {\n UserRepository = userRepository;\n UserLookupService = userLookupService;\n }\n\n public async Task HandleEventAsync(EntityUpdatedEto<UserEto> eventData)\n {\n var user = await UserRepository.FindAsync(eventData.Entity.Id);\n if (user != null)\n {\n if (user.Update(eventData.Entity))\n {\n await UserRepository.UpdateAsync(user);\n }\n }\n }\n}\n
\n\n
创建业务用户应用服务
\n\n以Employee为例
\n\n在应用层中创建EmployeeAppService,在这里我们实现对业务用户的增删改查操作。
\n\nEmployeeAppService继承自CrudAppService,它是ABP框架提供的增删改查的基类,其基类定义了增删改查的接口,包括GetAsync,GetListAsync,CreateAsync,UpdateAsync,DeleteAsync等。
\n\nOrganizationUnit为业务用户的查询接口的按组织架构查询提供查询依据。OrganizationUnitAppService注入到EmployeeAppService中。
\n\n\npublic class EmployeeAppService : CrudAppService<Employee, EmployeeDto, Guid, GetAllEmployeeInput, CreateEmployeeInput>, IEmployeeAppService\n{\n private readonly IOrganizationUnitAppService organizationUnitAppService;\n\n}\n
\n\n
增
\n\n创建CreateWithUserAsync方法,用于创建业务用户。
\n\n\npublic async Task<EmployeeDto> CreateWithUserAsync(CreateEmployeeWithUserInput input)\n{\n\n var createdUser = await identityUserAppService.CreateAsync(input);\n await CurrentUnitOfWork.SaveChangesAsync();\n var currentEmployee = await userLookupService.FindByIdAsync(createdUser.Id);\n ObjectMapper.Map(input, currentEmployee);\n var updatedEmployee = await Repository.UpdateAsync(currentEmployee);\n var result = ObjectMapper.Map<Employee, EmployeeDto>(updatedEmployee);\n\n if (input.OrganizationUnitId.HasValue)\n {\n await organizationUnitAppService.AddToOrganizationUnitAsync(\n new UserToOrganizationUnitInput()\n { UserId = createdUser.Id, OrganizationUnitId = input.OrganizationUnitId.Value });\n }\n return result;\n}\n
\n\n
删
\n\n删除接口由CrudAppService提供默认实现,无需重写。
\n\n改
\n\n创建UpdateWithUserAsync方法,用于更新业务用户。
\n\n\npublic async Task<EmployeeDto> UpdateWithUserAsync(CreateEmployeeInput input)\n{\n\n var currentEmployee = await userLookupService.FindByIdAsync(input.Id);\n if (currentEmployee == null)\n {\n throw new UserFriendlyException(\"没有找到对应的用户\");\n }\n ObjectMapper.Map(input, currentEmployee);\n var updatedEmployee = await Repository.UpdateAsync(currentEmployee);\n var result = ObjectMapper.Map<Employee, EmployeeDto>(updatedEmployee);\n\n return result;\n}\n\n
\n\n
查
\n\n查询单个实体接口由CrudAppService提供默认实现,无需重写。
\n\n查询集合:
\n\n以Employee为例,查询接口所需要的入参为:
\n\nOrganizationUnitId:按组织架构查询用户
\nIsWithoutOrganization:查询不属于任何组织架构的用户
\nEmployeeTitle:按职称查询用户
创建GetAllEmployeeInput,代码如下
\n\n\npublic class GetAllEmployeeInput : PagedAndSortedResultRequestDto\n{\n public string EmployeeTitle { get; set; }\n\n public Guid? OrganizationUnitId { get; set; }\n public bool IsWithoutOrganization { get; set; }\n\n}\n
\n\n
重写CreateFilteredQueryAsync
\n\n\n\nprotected override async Task<IQueryable<Employee>> CreateFilteredQueryAsync(GetAllEmployeeInput input)\n{\n var query = await ReadOnlyRepository.GetQueryableAsync().ConfigureAwait(continueOnCapturedContext: false);\n\n if (input.OrganizationUnitId.HasValue && !input.IsWithoutOrganization)\n {\n var organizationUnitUsers = await organizationUnitAppService.GetOrganizationUnitUsersAsync(new GetOrganizationUnitUsersInput()\n {\n Id = input.OrganizationUnitId.Value\n });\n if (organizationUnitUsers.Count() > 0)\n {\n var ids = organizationUnitUsers.Select(c => c.Id);\n query = query.Where(t => ids.Contains(t.Id));\n }\n else\n {\n query = query.Where(c => false);\n }\n }\n else if (input.IsWithoutOrganization)\n {\n var organizationUnitUsers = await organizationUnitAppService.GetUsersWithoutOrganizationAsync(new GetUserWithoutOrganizationInput());\n if (organizationUnitUsers.Count() > 0)\n {\n var ids = organizationUnitUsers.Select(c => c.Id);\n query = query.Where(t => ids.Contains(t.Id));\n }\n else\n {\n query = query.Where(c => false);\n }\n }\n query = query.WhereIf(!string.IsNullOrEmpty(input.EmployeeTitle), c => c.EmployeeTitle == input.EmployeeTitle);\n return query;\n}\n\n
\n\n
至此,我们已完成了对业务用户的增删改查功能实现。
\n\n创建控制器
\n\n在HttpApi项目中创建EmployeeController,代码如下:
\n\n\n[Area(HealthRemoteServiceConsts.ModuleName)]\n[RemoteService(Name = HealthRemoteServiceConsts.RemoteServiceName)]\n[Route(\"api/Health/employee\")]\npublic class EmployeeController : AbpControllerBase, IEmployeeAppService\n{\n private readonly IEmployeeAppService _employeeAppService;\n\n public EmployeeController(IEmployeeAppService employeeAppService)\n {\n _employeeAppService = employeeAppService;\n }\n\n [HttpPost]\n [Route(\"CreateWithUser\")]\n\n public Task<EmployeeDto> CreateWithUserAsync(CreateEmployeeWithUserInput input)\n {\n return _employeeAppService.CreateWithUserAsync(input);\n }\n\n [HttpDelete]\n [Route(\"Delete\")]\n public Task DeleteAsync(Guid id)\n {\n return _employeeAppService.DeleteAsync(id);\n }\n\n [HttpPut]\n [Route(\"UpdateWithUser\")]\n\n public Task<EmployeeDto> UpdateWithUserAsync(CreateEmployeeInput input)\n {\n return _employeeAppService.UpdateWithUserAsync(input);\n }\n\n [HttpGet]\n [Route(\"Get\")]\n public Task<EmployeeDto> GetAsync(Guid id)\n {\n return _employeeAppService.GetAsync(id);\n }\n\n [HttpGet]\n [Route(\"GetAll\")]\n public Task<PagedResultDto<EmployeeDto>> GetAllAsync(GetAllEmployeeInput input)\n {\n return _employeeAppService.GetAllAsync(input);\n }\n}
\n