From 10c00be2dc39e6d2c39328466ee1b77bad890e95 Mon Sep 17 00:00:00 2001 From: Necati Meral Date: Sun, 14 Jun 2020 22:20:11 +0200 Subject: [PATCH] Implemented rudimentary readonly appservices --- .../Services/AbstractKeyReadOnlyAppService.cs | 185 ++++++++++++++++++ .../Services/ReadOnlyAppService.cs | 45 +++++ 2 files changed, 230 insertions(+) create mode 100644 framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs create mode 100644 framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ReadOnlyAppService.cs diff --git a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs new file mode 100644 index 0000000000..c6a971cf5d --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Text; +using System.Threading.Tasks; + +using Volo.Abp.Application.Dtos; +using Volo.Abp.Auditing; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Repositories; + +namespace Volo.Abp.Application.Services +{ + public abstract class AbstractKeyReadOnlyAppService + : AbstractKeyReadOnlyAppService + where TEntity : class, IEntity + { + protected AbstractKeyReadOnlyAppService(IRepository repository) + : base(repository) + { + } + } + + public abstract class AbstractKeyReadOnlyAppService + : AbstractKeyReadOnlyAppService + where TEntity : class, IEntity + { + protected AbstractKeyReadOnlyAppService(IRepository repository) + : base(repository) + { + } + } + + public abstract class AbstractKeyReadOnlyAppService + : ApplicationService + , IReadOnlyAppService + where TEntity : class, IEntity + { + protected IRepository Repository { get; } + + protected virtual string GetPolicyName { get; set; } + + protected virtual string GetListPolicyName { get; set; } + + protected AbstractKeyReadOnlyAppService(IRepository repository) + { + Repository = repository; + } + + public virtual async Task GetAsync(TKey id) + { + await CheckGetPolicyAsync(); + + var entity = await GetEntityByIdAsync(id); + return MapToGetOutputDto(entity); + } + + public virtual async Task> GetListAsync(TGetListInput input) + { + await CheckGetListPolicyAsync(); + + var query = CreateFilteredQuery(input); + + var totalCount = await AsyncExecuter.CountAsync(query); + + query = ApplySorting(query, input); + query = ApplyPaging(query, input); + + var entities = await AsyncExecuter.ToListAsync(query); + + return new PagedResultDto( + totalCount, + entities.Select(MapToGetListOutputDto).ToList() + ); + } + + protected abstract Task GetEntityByIdAsync(TKey id); + + protected virtual async Task CheckGetPolicyAsync() + { + await CheckPolicyAsync(GetPolicyName); + } + + protected virtual async Task CheckGetListPolicyAsync() + { + await CheckPolicyAsync(GetListPolicyName); + } + + /// + /// Should apply sorting if needed. + /// + /// The query. + /// The input. + protected virtual IQueryable ApplySorting(IQueryable query, TGetListInput input) + { + //Try to sort query if available + if (input is ISortedResultRequest sortInput) + { + if (!sortInput.Sorting.IsNullOrWhiteSpace()) + { + return query.OrderBy(sortInput.Sorting); + } + } + + //IQueryable.Task requires sorting, so we should sort if Take will be used. + if (input is ILimitedResultRequest) + { + return ApplyDefaultSorting(query); + } + + //No sorting + return query; + } + + /// + /// Applies sorting if no sorting specified but a limited result requested. + /// + /// The query. + protected virtual IQueryable ApplyDefaultSorting(IQueryable query) + { + if (typeof(TEntity).IsAssignableTo()) + { + return query.OrderByDescending(e => ((ICreationAuditedObject)e).CreationTime); + } + + throw new AbpException("No sorting specified but this query requires sorting. Override the ApplyDefaultSorting method for your application service derived from AbstractKeyCrudAppService!"); + } + + /// + /// Should apply paging if needed. + /// + /// The query. + /// The input. + protected virtual IQueryable ApplyPaging(IQueryable query, TGetListInput input) + { + //Try to use paging if available + if (input is IPagedResultRequest pagedInput) + { + return query.PageBy(pagedInput); + } + + //Try to limit query result if available + if (input is ILimitedResultRequest limitedInput) + { + return query.Take(limitedInput.MaxResultCount); + } + + //No paging + return query; + } + + /// + /// This method should create based on given input. + /// It should filter query if needed, but should not do sorting or paging. + /// Sorting should be done in and paging should be done in + /// methods. + /// + /// The input. + protected virtual IQueryable CreateFilteredQuery(TGetListInput input) + { + return Repository; + } + + /// + /// Maps to . + /// It uses by default. + /// It can be overriden for custom mapping. + /// + protected virtual TGetOutputDto MapToGetOutputDto(TEntity entity) + { + return ObjectMapper.Map(entity); + } + + /// + /// Maps to . + /// It uses by default. + /// It can be overriden for custom mapping. + /// + protected virtual TGetListOutputDto MapToGetListOutputDto(TEntity entity) + { + return ObjectMapper.Map(entity); + } + } +} diff --git a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ReadOnlyAppService.cs b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ReadOnlyAppService.cs new file mode 100644 index 0000000000..b1176dca85 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ReadOnlyAppService.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Volo.Abp.Application.Dtos; +using Volo.Abp.Auditing; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Repositories; + +namespace Volo.Abp.Application.Services +{ + public abstract class ReadOnlyAppService + : AbstractKeyReadOnlyAppService + where TEntity : class, IEntity + where TGetOutputDto : IEntityDto + where TGetListOutputDto : IEntityDto + { + protected new IRepository Repository { get; } + + protected ReadOnlyAppService(IRepository repository) + : base(repository) + { + Repository = repository; + } + + protected override async Task GetEntityByIdAsync(TKey id) + { + return await Repository.GetAsync(id); + } + + protected override IQueryable ApplyDefaultSorting(IQueryable query) + { + if (typeof(TEntity).IsAssignableTo()) + { + return query.OrderByDescending(e => ((ICreationAuditedObject)e).CreationTime); + } + else + { + return query.OrderByDescending(e => e.Id); + } + } + } +}