Search code examples
asp.net-mvcentity-framework-6dtoaspnetboilerplateapplication-layer

Changing the output DTO (return value) of the GetAll method in an AsyncCrudAppService


I'm using ABP's AsyncCrudAppService in my AppServices. Here's my interface:

public interface IAssetRequisitionAppService : IAsyncCrudAppService
    <AssetRequisitionDto, Guid, GetAllInput, AssetRequisitionDto, AssetRequisitionDto, AssetRequisitionDetailsDto>
{ }

And the service:

public class AssetRequisitionAppService : AsyncCrudAppService
    <AssetRequisition, AssetRequisitionDto, Guid, GetAllInput, AssetRequisitionDto, AssetRequisitionDto, AssetRequisitionDetailsDto>, 
    IAssetRequisitionAppService
{
    public AssetRequisitionAppService(IRepository<AssetRequisition, Guid> repository) : base(repository)
    { }
}

Now, I believe all these standard CRUD methods will return the default type (which is AssetRequisitionDto in my case). But, what I want to do is to return a different type for Get() and GetAll() methods.

Get() should have a much more detailed DTO with subproperties of the Navigation props. But GetAll() should have a much less detailed one just to populate a table.

Is there a way to override the return types in some way?


Solution

  • Well I noticed I'll eventually need more complex filtering methods anyway. So, I created my custom types and methods.

    First, I created my own GetAllInput derived from PagedAndSortedResultRequestDto. It's suited for most of my services, as I usually need to query the data related to employees and locations:

    public class GetAllInput : PagedAndSortedResultRequestDto
    {
        public long? PersonId { get; set; }
        public long? LocationId { get; set; }
        public EEmployeeType? EmployeeType { get; set; }
    }
    

    After that I wrote a GetAll method for each of my services. They all return a PagedResultDto<> so I can use it's functionalities in presentation layer. Here's one example below:

    //MovableAppService
    
        public PagedResultDto<MovableLineDto> GetAllLinesRelatedToUser(GetAllInput input)
        {
            Logger.Info("Loading all movables related to current user");
    
            IQueryable<Movable> queryable = null;
            if (input.PersonId.HasValue)
            {
                if (input.EmployeeType == EEmployeeType.Recorder)
                {
                    var recorder = _personRepository.GetAll()
                    .OfType<Employee>()
                    .FirstOrDefault(x => x.Id == input.PersonId);
                    var authorizedStorageIds = recorder.StoragesAuthorized.Select(y => y.Id);
    
                    queryable = _repository.GetAll()
                        .Where(x => authorizedStorageIds.Contains(x.StorageOfOriginId));
                }
                else if (input.EmployeeType == EEmployeeType.UnitManager)
                {
                    var locationCodes = _locationRepository.GetAll()
                        .Where(x => x.ManagerInChargeId == input.PersonId)
                        .Select(x => x.Code);
    
                    foreach (var code in locationCodes)
                    {
                        queryable = _locationRepository.GetAll()
                            .Where(x => x.Code.StartsWith(code))
                            .SelectMany(x => x.AssignmentDocs)
                            .SelectMany(x => x.Movements)
                            .OfType<Assignment>()
                            .Where(x => x.TimeOfReturn == null)
                            .Select(x => x.Asset)
                            .OfType<Movable>();
                        queryable = queryable.Concat(queryable);
                    }
                }
                else if (input.TenantIdsOversee.Count() > 0)
                {
                    var overseer = _personRepository.GetAll()
                        .OfType<Overseer>()
                        .FirstOrDefault(x => x.Id == input.PersonId);
                    var overseeingTenantIds = overseer.TenantsOversee.Select(y => y.Id);
    
                    queryable = _repository.GetAll()
                       .Where(x => overseeingTenantIds.Contains((int)x.TenantId));
                }
                else if (input.EmployeeType == EEmployeeType.Employee)
                {
                    queryable = _personRepository.GetAll()
                        .OfType<Employee>()
                        .Where(x => x.Id == input.PersonId)
                        .SelectMany(x => x.AssignmentDocs)
                        .SelectMany(x => x.Movements)
                        .OfType<Assignment>()
                        .Where(x => x.TimeOfReturn == null)
                        .Select(x => x.Asset)
                        .OfType<Movable>();
                }
            }
            var list = queryable.ToList()
                    .OrderBy(x => x.Category.Definition);
            var items = _objectMapper.Map<IReadOnlyList<MovableLineDto>>(list);
    
            return new PagedResultDto<MovableLineDto>(items.Count, items);
        }
    

    Btw, aaron's answer is probably valid for ASP.NET Core projects. But my project is in MVC EF6, so those annotations are not available for me.

    Now I'm marking this as the answer but if there's a more elegant way, I'm happy to see and I'll change my mark then.