I would like to make an EF Core call that returns a parent object with a filtered list of associated children and projects it to a dto. I would like to do this via an EF Core Linq query, I suspect the ProjectTo part is ignoring the filtering up to that point. Is it possible?
I have another query that gets a parent and includes all child records without a filter so if possible I would like to implement something outside of the Dto mapping configuration.
Domain objects
public class ParentThing
{
public Guid Id { get; set; }
public string Name { get; set; }
public List<ChildThing> ChildThings { get; set; }
}
public class ChildThing
{
public Guid Id { get; set; }
public Guid ParentThingId { get; set; }
public DateTime Date { get; set; }
public ParentThing ParentThing { get; set; }
}
Dtos
public class ParentThingDto : IMapFrom<ParentThing>
{
public Guid Id { get; set; }
public string Name { get; set; }
public List<ChildThingDto> ChildThings { get; set; }
}
public class ChildThingDto : IMapFrom<ChildThing>
{
public Guid Id { get; set; }
public DateTime Date { get; set; }
}
Query
var upUntilDate = new DateTime(2013,1,1);
return await _context.ParentThings
.Where(x => x.Id == request.ParentThingId)
.Include(x => x.ChildThings.Where(y => y.Date <= upUntilDate))
.ProjectTo<ParentThingDto>(_mapper.ConfigurationProvider)
.FirstOrDefaultAsync();
What I get
{
"id": "a5c8f72a-4682-4f62-b231-4c77c0615b84",
"name": "Parent thing 9",
"childThings": [
{
"id": "ff5fda07-1c15-411c-b72e-e126b91513b3",
"date": "2014-06-26T22:41:20.7141034"
},
{
"id": "4dded8a3-2231-442e-b40a-1e114da2665a",
"date": "2012-04-02T06:51:31.963399"
}
]
}
What I expect/want
Note that I only get one child thing back instead of 2, this is because one child has a date after 2013-01-01 which is the filter point I would like.
{
"id": "a5c8f72a-4682-4f62-b231-4c77c0615b84",
"name": "Parent thing 9",
"childThings": [
{
"id": "4dded8a3-2231-442e-b40a-1e114da2665a",
"date": "2012-04-02T06:51:31.963399"
}
]
}
Just a note to say IMapFrom<T> only does the following
public interface IMapFrom<T>
{
void Mapping(Profile profile) => profile.CreateMap(typeof(T), GetType());
}
AFAIK Include does not work when you project to custom dto projections, either manually through Select or by using AutoMapper.
Instead, use a custom profile
public class CustomProfile : Profile
{
public CustomProfile()
{
DateTime? upUntilDate = null;
CreateMap<ParentThing, ParentThingDto>()
.ForMember(m => m.ChildThings, opt =>
opt.MapFrom(m => m.ChildThings.Where(y =>
upUntilDate.HasValue ? y.Date <= upUntilDate : true))
);
}
}
and then when you project you add the upUntilDate argument in the ProjectTo
var upUntilDate = new DateTime(2013,1,1);
return await _context.ParentThings
.Where(x => x.Id == request.ParentThingId)
.ProjectTo<ParentThingDto>(_mapper.ConfigurationProvider, new { upUntilDate })
.FirstOrDefaultAsync();
If you do not want to filter the children, just set upUntilDate to null (or do not add the argument).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With