简体   繁体   中英

EF Core and Automapper - filtering child records

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?

  • EF Core 5.0
  • Automapper 7.0.0

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).

This feature Filtered include was introduced in EF5

.Include(x => x.ChildThings.Where(y => y.Date <= upUntilDate))

before EF5 you are able to do like this

return await _context.ParentThings
  .Where(x => x.Id == request.ParentThingId)
  .Include(x => x.ChildThings)
  .Select(x=> new ParentThings{
     Id=x.Id,
     Name=x.Name
     ChildThings=x.ChildThings.Where(y => y.Date <= upUntilDate).ToList()
  }
  .ProjectTo<ParentThingDto>(_mapper.ConfigurationProvider)
  .FirstOrDefaultAsync();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM