forked from abpframework/abp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implemented rudimentary readonly appservices
- Loading branch information
1 parent
db2da83
commit 10c00be
Showing
2 changed files
with
230 additions
and
0 deletions.
There are no files selected for viewing
185 changes: 185 additions & 0 deletions
185
...c/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<TEntity, TEntityDto, TKey> | ||
: AbstractKeyReadOnlyAppService<TEntity, TEntityDto, TEntityDto, TKey, PagedAndSortedResultRequestDto> | ||
where TEntity : class, IEntity | ||
{ | ||
protected AbstractKeyReadOnlyAppService(IRepository<TEntity> repository) | ||
: base(repository) | ||
{ | ||
} | ||
} | ||
|
||
public abstract class AbstractKeyReadOnlyAppService<TEntity, TEntityDto, TKey, TGetListInput> | ||
: AbstractKeyReadOnlyAppService<TEntity, TEntityDto, TEntityDto, TKey, TGetListInput> | ||
where TEntity : class, IEntity | ||
{ | ||
protected AbstractKeyReadOnlyAppService(IRepository<TEntity> repository) | ||
: base(repository) | ||
{ | ||
} | ||
} | ||
|
||
public abstract class AbstractKeyReadOnlyAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput> | ||
: ApplicationService | ||
, IReadOnlyAppService<TGetOutputDto, TGetListOutputDto, TKey, TGetListInput> | ||
where TEntity : class, IEntity | ||
{ | ||
protected IRepository<TEntity> Repository { get; } | ||
|
||
protected virtual string GetPolicyName { get; set; } | ||
|
||
protected virtual string GetListPolicyName { get; set; } | ||
|
||
protected AbstractKeyReadOnlyAppService(IRepository<TEntity> repository) | ||
{ | ||
Repository = repository; | ||
} | ||
|
||
public virtual async Task<TGetOutputDto> GetAsync(TKey id) | ||
{ | ||
await CheckGetPolicyAsync(); | ||
|
||
var entity = await GetEntityByIdAsync(id); | ||
return MapToGetOutputDto(entity); | ||
} | ||
|
||
public virtual async Task<PagedResultDto<TGetListOutputDto>> 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<TGetListOutputDto>( | ||
totalCount, | ||
entities.Select(MapToGetListOutputDto).ToList() | ||
); | ||
} | ||
|
||
protected abstract Task<TEntity> GetEntityByIdAsync(TKey id); | ||
|
||
protected virtual async Task CheckGetPolicyAsync() | ||
{ | ||
await CheckPolicyAsync(GetPolicyName); | ||
} | ||
|
||
protected virtual async Task CheckGetListPolicyAsync() | ||
{ | ||
await CheckPolicyAsync(GetListPolicyName); | ||
} | ||
|
||
/// <summary> | ||
/// Should apply sorting if needed. | ||
/// </summary> | ||
/// <param name="query">The query.</param> | ||
/// <param name="input">The input.</param> | ||
protected virtual IQueryable<TEntity> ApplySorting(IQueryable<TEntity> 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; | ||
} | ||
|
||
/// <summary> | ||
/// Applies sorting if no sorting specified but a limited result requested. | ||
/// </summary> | ||
/// <param name="query">The query.</param> | ||
protected virtual IQueryable<TEntity> ApplyDefaultSorting(IQueryable<TEntity> query) | ||
{ | ||
if (typeof(TEntity).IsAssignableTo<ICreationAuditedObject>()) | ||
{ | ||
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!"); | ||
} | ||
|
||
/// <summary> | ||
/// Should apply paging if needed. | ||
/// </summary> | ||
/// <param name="query">The query.</param> | ||
/// <param name="input">The input.</param> | ||
protected virtual IQueryable<TEntity> ApplyPaging(IQueryable<TEntity> 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; | ||
} | ||
|
||
/// <summary> | ||
/// This method should create <see cref="IQueryable{TEntity}"/> based on given input. | ||
/// It should filter query if needed, but should not do sorting or paging. | ||
/// Sorting should be done in <see cref="ApplySorting"/> and paging should be done in <see cref="ApplyPaging"/> | ||
/// methods. | ||
/// </summary> | ||
/// <param name="input">The input.</param> | ||
protected virtual IQueryable<TEntity> CreateFilteredQuery(TGetListInput input) | ||
{ | ||
return Repository; | ||
} | ||
|
||
/// <summary> | ||
/// Maps <see cref="TEntity"/> to <see cref="TGetOutputDto"/>. | ||
/// It uses <see cref="IObjectMapper"/> by default. | ||
/// It can be overriden for custom mapping. | ||
/// </summary> | ||
protected virtual TGetOutputDto MapToGetOutputDto(TEntity entity) | ||
{ | ||
return ObjectMapper.Map<TEntity, TGetOutputDto>(entity); | ||
} | ||
|
||
/// <summary> | ||
/// Maps <see cref="TEntity"/> to <see cref="TGetListOutputDto"/>. | ||
/// It uses <see cref="IObjectMapper"/> by default. | ||
/// It can be overriden for custom mapping. | ||
/// </summary> | ||
protected virtual TGetListOutputDto MapToGetListOutputDto(TEntity entity) | ||
{ | ||
return ObjectMapper.Map<TEntity, TGetListOutputDto>(entity); | ||
} | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ReadOnlyAppService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput> | ||
: AbstractKeyReadOnlyAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput> | ||
where TEntity : class, IEntity<TKey> | ||
where TGetOutputDto : IEntityDto<TKey> | ||
where TGetListOutputDto : IEntityDto<TKey> | ||
{ | ||
protected new IRepository<TEntity, TKey> Repository { get; } | ||
|
||
protected ReadOnlyAppService(IRepository<TEntity, TKey> repository) | ||
: base(repository) | ||
{ | ||
Repository = repository; | ||
} | ||
|
||
protected override async Task<TEntity> GetEntityByIdAsync(TKey id) | ||
{ | ||
return await Repository.GetAsync(id); | ||
} | ||
|
||
protected override IQueryable<TEntity> ApplyDefaultSorting(IQueryable<TEntity> query) | ||
{ | ||
if (typeof(TEntity).IsAssignableTo<ICreationAuditedObject>()) | ||
{ | ||
return query.OrderByDescending(e => ((ICreationAuditedObject)e).CreationTime); | ||
} | ||
else | ||
{ | ||
return query.OrderByDescending(e => e.Id); | ||
} | ||
} | ||
} | ||
} |