Skip to content

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

License

Notifications You must be signed in to change notification settings

EasyAbp/Abp.RelatedDtoLoader

Repository files navigation

Abp.RelatedDtoLoader

NuGet NuGet Download

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)

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

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; }
    
    	//Automatic matching rules $"{nameof(Product)}Id"
    	[RelatedDto]
    	public ProductDto Product { get; set; }
    
    	//Manually matching the ProductId
    	[RelatedDto(nameof(ProductId))]
    	public ProductDto ProductInfo { 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 = await _orderRepository.GetAsync(id);
    
    		var orderDto = ObjectMapper.Map<Order, OrderDto>(order);
    
    		//LoadAsync
    		return await _relatedDtoLoader.LoadAsync(orderDto);   // orderDto.Product should have been loaded.
    	}
    	
    	protected override async Task<List<OrderDto>> MapToGetListOutputDtosAsync(List<Order> entities)
    	{
    		var orderDtos = await base.MapToGetListOutputDtosAsync(entities);
    		
    		//LoadListAsync
    		return (await _relatedDtoLoader.LoadListAsync(orderDtos)).ToList(); // OrderDto.Product should have been loaded.
    	}
    }

See more: Custom DTO source examples.

Roadmap

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

Thanks @wakuflair and @itryan for their contribution in the first version.

About

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

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors 4

  •  
  •  
  •  
  •