ビジネスユーザーの作成
ビジネスユーザー(BusinessUser)は、アイデンティティ管理モジュール(Identity module)の認証済みユーザーIdentityUserとは異なり、業務システムにおける「ユーザー」の定義を中心としたドメインモデルです。たとえば、病院システムでは、ビジネス ユーザーは医師、看護師、患者などであり、OA システムでは、ビジネス ユーザーは従業員、管理者、顧客などです。
ビジネス ユーザーと認証ユーザーは同期メカニズムによって関連付けられ、ビジネス ユーザーは分散イベントのシンクロナイザー (DistributedEvent) を通じて認証ユーザーと関連付けられ、同期されます。
Health ビジネス モジュールでは、次の 2 種類のビジネス ユーザーが定義されています。
クライアント: クライアント;
従業員:従業員。
これらのビジネス ユーザーは、ビジネス ユーザーの基本クラスであり、名前、性別、生年月日、ID 番号などのビジネス ユーザーの基本情報が含まれる HealthUser から継承します。また、認証ユーザー情報を同期するときにビジネス ユーザーの基本情報を更新するには、IUpdateUserData インターフェイスを実装する必要があります。
従業員には、従業員番号、役職、プロフィールなどの情報が含まれます。そのドメイン モデルは次のように定義されます。
public class Employee : HealthUser<Guid>, IUser, IUpdateUserData
{
[StringLength(12)]
public string EmployeeNumber { get; set; }
[StringLength(64)]
public string EmployeeTitle { get; set; }
public string Introduction { get; set; }
...
}
クライアントには、顧客番号、身長、体重、婚姻状況、その他の情報が含まれます。そのドメイン モデルは次のように定義されます。
public class Client : HealthUser<Guid>, IUser, IUpdateUserData
{
//unique
[StringLength(12)]
public string ClientNumber { get; set; }
public string ClientNumberType { get; set; }
[Range(0.0, 250.0)]
public double? Height { get; set; }
[Range(0.0, 1000.0)]
public double? Weight { get; set; }
public string Marriage { get; set; }
public string Status { get; set; }
}
ビジネス ユーザー シンクロナイザーを作成する
Client を例にとると、ClientLookupService はビジネス ユーザー向けのクエリ サービスであり、その基本クラス UserLookupService は、ID によるクエリ、ユーザー名によるクエリ、組織構造によるクエリ、世帯関係によるクエリなどを含む、関連するユーザーのクエリ インターフェイスを定義します。
ClientLookupService を作成します。コードは次のとおりです。
public class ClientLookupService : UserLookupService<Client, IClientRepository>, IClientLookupService
{
public ClientLookupService(
IClientRepository userRepository,
IUnitOfWorkManager unitOfWorkManager)
: base(
userRepository,
unitOfWorkManager)
{
}
protected override Client CreateUser(IUserData externalUser)
{
return new Client(externalUser);
}
}
シンクロナイザーは分散イベント EntityUpdatedEto をサブスクライブし、認証ユーザーが更新されるとビジネス ユーザーの基本情報を更新します。
ClientSynchronizer を作成します。コードは次のとおりです。
public class ClientSynchronizer :
IDistributedEventHandler<EntityUpdatedEto<UserEto>>,
ITransientDependency
{
protected IClientRepository UserRepository { get; }
protected IClientLookupService UserLookupService { get; }
public ClientSynchronizer(
IClientRepository userRepository,
IClientLookupService userLookupService)
{
UserRepository = userRepository;
UserLookupService = userLookupService;
}
public async Task HandleEventAsync(EntityUpdatedEto<UserEto> eventData)
{
var user = await UserRepository.FindAsync(eventData.Entity.Id);
if (user != null)
{
if (user.Update(eventData.Entity))
{
await UserRepository.UpdateAsync(user);
}
}
}
}
ビジネス ユーザー アプリケーション サービスの作成
従業員を例に挙げてみましょう
アプリケーション層に EmployeeAppService を作成し、ビジネス ユーザー向けの追加、削除、変更、クエリ操作を実装します。
EmployeeAppService は、ABP フレームワークによって提供される追加、削除、変更、およびクエリの基本クラスである CrudAppService を継承します。その基本クラスは、GetAsync、GetListAsync、CreateAsync、UpdateAsync、DeleteAsync、などの追加、削除、変更、およびクエリのインターフェイスを定義します。等
OrganizationUnit は、ビジネス ユーザーのクエリ インターフェイスに、組織構造ごとにクエリを実行するためのクエリ ベースを提供します。OrganizationUnitAppService は EmployeeAppService に挿入されます。
public class EmployeeAppService : CrudAppService<Employee, EmployeeDto, Guid, GetAllEmployeeInput, CreateEmployeeInput>, IEmployeeAppService
{
private readonly IOrganizationUnitAppService organizationUnitAppService;
}
増加
ビジネス ユーザーを作成するための CreateWithUserAsync メソッドを作成します。
public async Task<EmployeeDto> CreateWithUserAsync(CreateEmployeeWithUserInput input)
{
var createdUser = await identityUserAppService.CreateAsync(input);
await CurrentUnitOfWork.SaveChangesAsync();
var currentEmployee = await userLookupService.FindByIdAsync(createdUser.Id);
ObjectMapper.Map(input, currentEmployee);
var updatedEmployee = await Repository.UpdateAsync(currentEmployee);
var result = ObjectMapper.Map<Employee, EmployeeDto>(updatedEmployee);
if (input.OrganizationUnitId.HasValue)
{
await organizationUnitAppService.AddToOrganizationUnitAsync(
new UserToOrganizationUnitInput()
{ UserId = createdUser.Id, OrganizationUnitId = input.OrganizationUnitId.Value });
}
return result;
}
消去
削除インターフェイスはデフォルトで CrudAppService によって提供されており、書き直す必要はありません。
変化
ビジネス ユーザーを更新するための UpdateWithUserAsync メソッドを作成します。
public async Task<EmployeeDto> UpdateWithUserAsync(CreateEmployeeInput input)
{
var currentEmployee = await userLookupService.FindByIdAsync(input.Id);
if (currentEmployee == null)
{
throw new UserFriendlyException("没有找到对应的用户");
}
ObjectMapper.Map(input, currentEmployee);
var updatedEmployee = await Repository.UpdateAsync(currentEmployee);
var result = ObjectMapper.Map<Employee, EmployeeDto>(updatedEmployee);
return result;
}
チェック
単一エンティティ インターフェイスのクエリのデフォルト実装は CrudAppService によって提供されており、書き直す必要はありません。
クエリコレクション:
従業員を例にとると、クエリ インターフェイスに必要な入力パラメータは次のとおりです。
OrganizationUnitId: 組織構造ごとにユーザーをクエリ
IsWithoutOrganization: どの組織構造にも属さないユーザーをクエリ
EmployeeTitle: 役職ごとにユーザーをクエリ
GetAllEmployeeInput を作成します。コードは次のとおりです。
public class GetAllEmployeeInput : PagedAndSortedResultRequestDto
{
public string EmployeeTitle { get; set; }
public Guid? OrganizationUnitId { get; set; }
public bool IsWithoutOrganization { get; set; }
}
CreateFilteredQueryAsync をオーバーライドする
protected override async Task<IQueryable<Employee>> CreateFilteredQueryAsync(GetAllEmployeeInput input)
{
var query = await ReadOnlyRepository.GetQueryableAsync().ConfigureAwait(continueOnCapturedContext: false);
if (input.OrganizationUnitId.HasValue && !input.IsWithoutOrganization)
{
var organizationUnitUsers = await organizationUnitAppService.GetOrganizationUnitUsersAsync(new GetOrganizationUnitUsersInput()
{
Id = input.OrganizationUnitId.Value
});
if (organizationUnitUsers.Count() > 0)
{
var ids = organizationUnitUsers.Select(c => c.Id);
query = query.Where(t => ids.Contains(t.Id));
}
else
{
query = query.Where(c => false);
}
}
else if (input.IsWithoutOrganization)
{
var organizationUnitUsers = await organizationUnitAppService.GetUsersWithoutOrganizationAsync(new GetUserWithoutOrganizationInput());
if (organizationUnitUsers.Count() > 0)
{
var ids = organizationUnitUsers.Select(c => c.Id);
query = query.Where(t => ids.Contains(t.Id));
}
else
{
query = query.Where(c => false);
}
}
query = query.WhereIf(!string.IsNullOrEmpty(input.EmployeeTitle), c => c.EmployeeTitle == input.EmployeeTitle);
return query;
}
これまでに、ビジネス ユーザー向けの追加、削除、変更、クエリ機能の実装が完了しました。
コントローラーの作成
HttpApi プロジェクトに EmployeeController を作成します。コードは次のとおりです。
[Area(HealthRemoteServiceConsts.ModuleName)]
[RemoteService(Name = HealthRemoteServiceConsts.RemoteServiceName)]
[Route("api/Health/employee")]
public class EmployeeController : AbpControllerBase, IEmployeeAppService
{
private readonly IEmployeeAppService _employeeAppService;
public EmployeeController(IEmployeeAppService employeeAppService)
{
_employeeAppService = employeeAppService;
}
[HttpPost]
[Route("CreateWithUser")]
public Task<EmployeeDto> CreateWithUserAsync(CreateEmployeeWithUserInput input)
{
return _employeeAppService.CreateWithUserAsync(input);
}
[HttpDelete]
[Route("Delete")]
public Task DeleteAsync(Guid id)
{
return _employeeAppService.DeleteAsync(id);
}
[HttpPut]
[Route("UpdateWithUser")]
public Task<EmployeeDto> UpdateWithUserAsync(CreateEmployeeInput input)
{
return _employeeAppService.UpdateWithUserAsync(input);
}
[HttpGet]
[Route("Get")]
public Task<EmployeeDto> GetAsync(Guid id)
{
return _employeeAppService.GetAsync(id);
}
[HttpGet]
[Route("GetAll")]
public Task<PagedResultDto<EmployeeDto>> GetAllAsync(GetAllEmployeeInput input)
{
return _employeeAppService.GetAllAsync(input);
}
}