# Abp.RelatedDtoLoader

ABP version (opens new window) NuGet (opens new window) NuGet Download (opens new window) GitHub stars (opens new window)

An Abp module that help you automatically load related DTO (like ProductDto in OrderDto) under DDD.

# Installation

  1. Install the following NuGet packages. (see how (opens new window))

    • EasyAbp.Abp.RelatedDtoLoader
    • EasyAbp.Abp.RelatedDtoLoader.Abstractions
  2. Add DependsOn(typeof(AbpRelatedDtoLoaderModule)) attribute to configure the module dependencies. (see how (opens new window))

# Usage

  1. Make your Order entity (or aggregate root) like this.

    public class Order : AggregateRoot<Guid>
    {
        public virtual Guid ProductId { get; protected set; }
    
        // do not add navigation properties to other aggregate roots!
        // public virtual Product Product { get; set; }
    
        protected Order() { }
    
        public Order(Guid id, Guid productId) : base(id)
        {
            ProductId = productId;
        }
    }
    
  2. Add RelatedDto attribute in OrderDto.

    public class OrderDto : EntityDto<Guid>
    {
    	public Guid ProductId { get; set; }
    
    	[RelatedDto]
    	public ProductDto Product { get; set; }
    }
    
  3. Create MyProjectRelatedDtoLoaderProfile and add a rule.

    public class MyProjectRelatedDtoLoaderProfile : RelatedDtoLoaderProfile
    {
    	public MyRelatedDtoLoaderProfile()
    	{
    		// the following example gets entities from a repository and maps them to DTOs.
    		UseRepositoryLoader<ProductDto, Product>();
    
    		// or load it by a customized function.
    		UseLoader(GetOrderDtosAsync);
    
    		// a target type need to be enabled to load its related Dtos properties.
    		// LoadForDto<OrderDto>();
    	}
    }
    
  4. Configure the RelatedDtoLoader to use the profile.

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
    	// ...
    
    	Configure<RelatedDtoLoaderOptions>(options =>
    	{
    		// add the Profile
    		options.AddProfile<MyProjectRelatedDtoLoaderProfile>();
    	});
    
    	// ...
    }
    
  5. Enable the target type to load its related Dto properties.

    either in the Profile

    public class MyProjectRelatedDtoLoaderProfile : RelatedDtoLoaderProfile
    {
    	public MyRelatedDtoLoaderProfile()
    	{
    		// ...
    
    		// a target type need to be enabled to load its related Dtos properties.
    		LoadForDto<OrderDto>();
    	}
    }
    

    or via RegisterTargetDtosInModule method of RelatedDtoLoaderOptions

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
    	// ...
    
    	Configure<RelatedDtoLoaderOptions>(options =>
    	{                                
    		// adding module will auto register all the target dto types which contain any property with RelatedDto attribute.
    		options.LoadForDtosInModule<MyApplicationContractsModule>();
    	});
    
    	// ...
    }
    
  6. Try to get OrderDto with ProductDto.

    public class OrderAppService : ApplicationService, IOrderAppService
    {
    	private readonly IRelatedDtoLoader _relatedDtoLoader;
    	private readonly IRepository<Order, Guid> _orderRepository;
    
    	public OrderAppService(IRelatedDtoLoader relatedDtoLoader, IRepository<Order, Guid> orderRepository)
    	{
    		_relatedDtoLoader = relatedDtoLoader;
    		_orderRepository = orderRepository;
    	}
    
    	public async Task<OrderDto> GetAsync(Guid id)
    	{
    		var order = _orderRepository.GetAsync(id);
    
    		var orderDto = ObjectMapper.Map<Order, OrderDto>(order);
    
    		return await _relatedDtoLoader.LoadAsync(orderDto);   // orderDto.Product should have been loaded.
    	}
    }
    

See more: Custom DTO source examples.

# Roadmap

  • [x] Custom DTO source
  • [x] Support one-to-many relation
  • [x] Support non Guid keys
  • [x] Support multi module development
  • [ ] Support nested DTOs loading
  • [ ] Get duplicate DTO from memory
  • [ ] DTO cache
  • [ ] An option to enable loading deleted DTO
  • [x] Unit test

Thanks @wakuflair (opens new window) and @itryan (opens new window) for their contribution in the first version.

Last Updated: 12/28/2020, 9:21:19 AM