Browse Source

Merge pull request #4346 from NecatiMeral/split-crudappservice

Split `ICrudAppservice` and implementations
pull/4536/head
maliming 6 years ago
committed by GitHub
parent
commit
c014a1f533
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Services/ICreateAppService.cs
  2. 21
      framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Services/ICreateUpdateAppService.cs
  3. 13
      framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Services/ICrudAppService.cs
  4. 9
      framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Services/IDeleteAppService.cs
  5. 25
      framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Services/IReadOnlyAppService.cs
  6. 16
      framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Services/IUpdateAppService.cs
  7. 161
      framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyCrudAppService.cs
  8. 184
      framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs
  9. 2
      framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/CrudAppService.cs
  10. 66
      framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ReadOnlyAppService.cs

16
framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Services/ICreateAppService.cs

@ -0,0 +1,16 @@
using System.Threading.Tasks;
namespace Volo.Abp.Application.Services
{
public interface ICreateAppService<TEntityDto>
: ICreateAppService<TEntityDto, TEntityDto>
{
}
public interface ICreateAppService<TGetOutputDto, in TCreateInput>
: IApplicationService
{
Task<TGetOutputDto> CreateAsync(TCreateInput input);
}
}

21
framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Services/ICreateUpdateAppService.cs

@ -0,0 +1,21 @@
namespace Volo.Abp.Application.Services
{
public interface ICreateUpdateAppService<TEntityDto, in TKey>
: ICreateUpdateAppService<TEntityDto, TKey, TEntityDto, TEntityDto>
{
}
public interface ICreateUpdateAppService<TEntityDto, in TKey, in TCreateUpdateInput>
: ICreateUpdateAppService<TEntityDto, TKey, TCreateUpdateInput, TCreateUpdateInput>
{
}
public interface ICreateUpdateAppService<TGetOutputDto, in TKey, in TCreateUpdateInput, in TUpdateInput>
: ICreateAppService<TGetOutputDto, TCreateUpdateInput>,
IUpdateAppService<TGetOutputDto, TKey, TUpdateInput>
{
}
}

13
framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Services/ICrudAppService.cs

@ -1,4 +1,3 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
namespace Volo.Abp.Application.Services
@ -28,16 +27,10 @@ namespace Volo.Abp.Application.Services
}
public interface ICrudAppService<TGetOutputDto, TGetListOutputDto, in TKey, in TGetListInput, in TCreateInput, in TUpdateInput>
: IApplicationService
: IReadOnlyAppService<TGetOutputDto, TGetListOutputDto, TKey, TGetListInput>,
ICreateUpdateAppService<TGetOutputDto, TKey, TCreateInput, TUpdateInput>,
IDeleteAppService<TKey>
{
Task<TGetOutputDto> GetAsync(TKey id);
Task<PagedResultDto<TGetListOutputDto>> GetListAsync(TGetListInput input);
Task<TGetOutputDto> CreateAsync(TCreateInput input);
Task<TGetOutputDto> UpdateAsync(TKey id, TUpdateInput input);
Task DeleteAsync(TKey id);
}
}

9
framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Services/IDeleteAppService.cs

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace Volo.Abp.Application.Services
{
public interface IDeleteAppService<in TKey> : IApplicationService
{
Task DeleteAsync(TKey id);
}
}

25
framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Services/IReadOnlyAppService.cs

@ -0,0 +1,25 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
namespace Volo.Abp.Application.Services
{
public interface IReadOnlyAppService<TEntityDto, in TKey>
: IReadOnlyAppService<TEntityDto, TEntityDto, TKey, PagedAndSortedResultRequestDto>
{
}
public interface IReadOnlyAppService<TEntityDto, in TKey, in TGetListInput>
: IReadOnlyAppService<TEntityDto, TEntityDto, TKey, TGetListInput>
{
}
public interface IReadOnlyAppService<TGetOutputDto, TGetListOutputDto, in TKey, in TGetListInput>
: IApplicationService
{
Task<TGetOutputDto> GetAsync(TKey id);
Task<PagedResultDto<TGetListOutputDto>> GetListAsync(TGetListInput input);
}
}

16
framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Services/IUpdateAppService.cs

@ -0,0 +1,16 @@
using System.Threading.Tasks;
namespace Volo.Abp.Application.Services
{
public interface IUpdateAppService<TEntityDto, in TKey>
: IUpdateAppService<TEntityDto, TKey, TEntityDto>
{
}
public interface IUpdateAppService<TGetOutputDto, in TKey, in TUpdateInput>
: IApplicationService
{
Task<TGetOutputDto> UpdateAsync(TKey id, TUpdateInput input);
}
}

161
framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyCrudAppService.cs

@ -1,9 +1,6 @@
using System;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.MultiTenancy;
@ -61,17 +58,12 @@ namespace Volo.Abp.Application.Services
}
public abstract class AbstractKeyCrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
: ApplicationService,
: AbstractKeyReadOnlyAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput>,
ICrudAppService<TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
where TEntity : class, IEntity
{
protected IRepository<TEntity> Repository { get; }
protected virtual string GetPolicyName { get; set; }
protected virtual string GetListPolicyName { get; set; }
protected virtual string CreatePolicyName { get; set; }
protected virtual string UpdatePolicyName { get; set; }
@ -79,37 +71,11 @@ namespace Volo.Abp.Application.Services
protected virtual string DeletePolicyName { get; set; }
protected AbstractKeyCrudAppService(IRepository<TEntity> repository)
: base(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()
);
}
public virtual async Task<TGetOutputDto> CreateAsync(TCreateInput input)
{
await CheckCreatePolicyAsync();
@ -144,18 +110,6 @@ namespace Volo.Abp.Application.Services
protected abstract Task DeleteByIdAsync(TKey id);
protected abstract Task<TEntity> GetEntityByIdAsync(TKey id);
protected virtual async Task CheckGetPolicyAsync()
{
await CheckPolicyAsync(GetPolicyName);
}
protected virtual async Task CheckGetListPolicyAsync()
{
await CheckPolicyAsync(GetListPolicyName);
}
protected virtual async Task CheckCreatePolicyAsync()
{
await CheckPolicyAsync(CreatePolicyName);
@ -171,101 +125,6 @@ namespace Volo.Abp.Application.Services
await CheckPolicyAsync(DeletePolicyName);
}
/// <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);
}
/// <summary>
/// Maps <see cref="TCreateInput"/> to <see cref="TEntity"/> to create a new entity.
/// It uses <see cref="IObjectMapper"/> by default.
@ -284,18 +143,14 @@ namespace Volo.Abp.Application.Services
/// </summary>
protected virtual void SetIdForGuids(TEntity entity)
{
var entityWithGuidId = entity as IEntity<Guid>;
if (entityWithGuidId == null || entityWithGuidId.Id != Guid.Empty)
if (entity is IEntity<Guid> entityWithGuidId && entityWithGuidId.Id == Guid.Empty)
{
return;
EntityHelper.TrySetId(
entityWithGuidId,
() => GuidGenerator.Create(),
true
);
}
EntityHelper.TrySetId(
entityWithGuidId,
() => GuidGenerator.Create(),
true
);
}
/// <summary>

184
framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs

@ -0,0 +1,184 @@
using System;
using System.Linq;
using System.Linq.Dynamic.Core;
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(IReadOnlyRepository<TEntity> repository)
: base(repository)
{
}
}
public abstract class AbstractKeyReadOnlyAppService<TEntity, TEntityDto, TKey, TGetListInput>
: AbstractKeyReadOnlyAppService<TEntity, TEntityDto, TEntityDto, TKey, TGetListInput>
where TEntity : class, IEntity
{
protected AbstractKeyReadOnlyAppService(IReadOnlyRepository<TEntity> repository)
: base(repository)
{
}
}
public abstract class AbstractKeyReadOnlyAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput>
: ApplicationService
, IReadOnlyAppService<TGetOutputDto, TGetListOutputDto, TKey, TGetListInput>
where TEntity : class, IEntity
{
protected IReadOnlyRepository<TEntity> ReadOnlyRepository { get; }
protected virtual string GetPolicyName { get; set; }
protected virtual string GetListPolicyName { get; set; }
protected AbstractKeyReadOnlyAppService(IReadOnlyRepository<TEntity> repository)
{
ReadOnlyRepository = 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 AbstractKeyReadOnlyAppService!");
}
/// <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 ReadOnlyRepository;
}
/// <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);
}
}
}

2
framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/CrudAppService.cs

@ -70,7 +70,7 @@ namespace Volo.Abp.Application.Services
protected new IRepository<TEntity, TKey> Repository { get; }
protected CrudAppService(IRepository<TEntity, TKey> repository)
: base(repository)
: base(repository)
{
Repository = repository;
}

66
framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ReadOnlyAppService.cs

@ -0,0 +1,66 @@
using System;
using System.Linq;
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, TEntityDto, TKey>
: ReadOnlyAppService<TEntity, TEntityDto, TEntityDto, TKey, PagedAndSortedResultRequestDto>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected ReadOnlyAppService(IReadOnlyRepository<TEntity, TKey> repository)
: base(repository)
{
}
}
public abstract class ReadOnlyAppService<TEntity, TEntityDto, TKey, TGetListInput>
: ReadOnlyAppService<TEntity, TEntityDto, TEntityDto, TKey, TGetListInput>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected ReadOnlyAppService(IReadOnlyRepository<TEntity, TKey> repository)
: base(repository)
{
}
}
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 IReadOnlyRepository<TEntity, TKey> Repository { get; }
protected ReadOnlyAppService(IReadOnlyRepository<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);
}
}
}
}
Loading…
Cancel
Save