I have three related entities A
, B
and C
where A
is the parent of B
and B
is the parent of C
.
public class A
{
public int Id { get; set; }
public B B { get; set; }
}
public class B
{
public int Id { get; set; }
public C C { get; set; }
}
public class C
{
public int Id { get; set; }
public string Name { get; set; }
}
The entities above have their own DTO models which contain FromEntity
method and Projection
.
public class ADto
{
public int Id { get; set; }
public BDto BDto { get; set; }
public static Expression<Func<A, ADto>> Projection
{
get
{
return x => new ADto
{
Id = x.Id,
BDto = BDto.FromEntity(x.B)
};
}
}
}
public class BDto
{
public int Id { get; set; }
public CDto CDto { get; set; }
public static Expression<Func<B, BDto>> Projection
{
get
{
return x => new BDto
{
Id = x.Id,
CDto = CDto.FromEntity(x.C)
};
}
}
public static BDto FromEntity(B entity)
{
return Projection.Compile().Invoke(entity);
}
}
public class CDto
{
public int Id { get; set; }
public string Name { get; set; }
public static Expression<Func<C, CDto>> Projection
{
get
{
return x => new CDto
{
Id = x.Id,
Name = x.Name
};
}
}
public static CDto FromEntity(C entity)
{
return Projection.Compile().Invoke(entity);
}
}
Then I use projection like this:
_context.A.Where(x = x.Id == id).Select(ADto.Projection).FirstOrDefault();
All my current attempts ended up with the exception in CDto
in FromEntity
method, because the entity is null and therefore the projection can not be invoked.
System.NullReferenceException: 'Object reference not set to an instance of an object.'
Is there any way to chain more nested projections?
I am aware that I can use this:
public class ADto
{
public int Id { get; set; }
public BDto BDto { get; set; }
public static Expression<Func<A, ADto>> Projection
{
get
{
return x => new ADto
{
Id = x.Id,
BDto = new BDto()
{
Id = x.B.Id,
CDto = new CDto()
{
Id = x.B.C.Id,
Name = x.B.C.Name
}
}
};
}
}
}
But I would like to manage projection in one place, because real classes are too complicated.
I have been using Automapper for quite some time in .NET Core projects due to ease of use and built-in dependency injection. It can handle nested object mappings.
Install from PM:
Install-Package AutoMapper
Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection
Register in the Startup.cs, ConfigureServices method:
services.AddAutoMapper(typeof(Startup));
Create a class to keep your mappings, e.g. MappingProfile.cs
using Profile from automapper, you can define mappings.
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<A, ADto>();
CreateMap<B, BDto>();
CreateMap<C, CDto>();
}
}
The above mapping tells automapper that the entity can be mapped to DTO.
In your controller, you can inject an IMapper
private readonly IMapper _mapper;
public MyController(IMapper mapper)
{
_mapper = mapper;
}
and map values like below:
var dto = _mapper.Map<A>(a); // Map object to dto, which will map nested objects.