# Abp.RelatedDtoLoader
(opens new window) (opens new window) (opens new window) (opens new window) (opens new window)
An Abp module that help you automatically load related DTO (like ProductDto in OrderDto) under DDD.
# Installation
Install the following NuGet packages. (see how (opens new window))
- EasyAbp.Abp.RelatedDtoLoader
- EasyAbp.Abp.RelatedDtoLoader.Abstractions
Add
DependsOn(typeof(AbpRelatedDtoLoaderModule))
attribute to configure the module dependencies. (see how (opens new window))
# Usage
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; } }
Add
RelatedDto
attribute inOrderDto
.public class OrderDto : EntityDto<Guid> { public Guid ProductId { get; set; } [RelatedDto] public ProductDto Product { get; set; } }
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>(); } }
Configure the RelatedDtoLoader to use the profile.
public override void ConfigureServices(ServiceConfigurationContext context) { // ... Configure<RelatedDtoLoaderOptions>(options => { // add the Profile options.AddProfile<MyProjectRelatedDtoLoaderProfile>(); }); // ... }
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 RelatedDtoLoaderOptionspublic 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>(); }); // ... }
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.