EF Core和Automapper - 过滤子记录

3
我希望进行一个EF Core调用,返回一个带有过滤的关联子列表的父对象,并将其投影到dto。我希望通过EF Core Linq查询来实现这一点,我怀疑ProjectTo部分忽略了到那个点的过滤。这可能吗?
  • EF Core 5.0
  • Automapper 7.0.0
我有另一个查询,获取一个父级并包含所有子记录而没有过滤器,所以如果可能的话,我想在Dto映射配置之外实现某些东西。 领域对象
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; }
}

查询

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();

我可以为您提供什么

{
  "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"
    }
  ]
}

我期望的/想要的

请注意,我只收到了一个子项而不是两个,这是因为其中一个子项的日期在2013-01-01之后,这是我想要的过滤点。

{
  "id": "a5c8f72a-4682-4f62-b231-4c77c0615b84",
  "name": "Parent thing 9",
  "childThings": [
    {
      "id": "4dded8a3-2231-442e-b40a-1e114da2665a",
      "date": "2012-04-02T06:51:31.963399"
    }
  ]
}

这里提醒一下,IMapFrom<T> 只有以下功能:

public interface IMapFrom<T>
{   
    void Mapping(Profile profile) => profile.CreateMap(typeof(T), GetType());
}

你可以在 AM 配置中编写筛选器,这样你就不需要像 ProjectTo 一样使用 Include - Lucian Bargaoanu
谢谢@LucianBargaoanu,我已经编辑了问题以使其更清晰;有时候我想要获取父记录而不应用筛选,并且能够共享每个查询的Dto对象。希望这是可能的,但我不确定。 - CT14.IT
2个回答

5
据我所知,在通过手动使用 Select 或使用 AutoMapper 时,当您投影到自定义dto投影时,Include不能正常工作。相反,请使用自定义配置文件。
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))
                    );
        }
    }

然后在投影时,在 ProjectTo 中添加 upUntilDate 参数。

var upUntilDate = new DateTime(2013,1,1);

return await _context.ParentThings
  .Where(x => x.Id == request.ParentThingId)
  .ProjectTo<ParentThingDto>(_mapper.ConfigurationProvider, new { upUntilDate })
  .FirstOrDefaultAsync();

如果您不想过滤子级,请将upUntilDate设置为null(或不添加该参数)。


谢谢你的帮助,我稍微修改了一下以适应我的项目结构(并且删除了.ToList()部分),这在使用Automatter / EF Core时是有效的。理想情况下,我希望避免在映射中进行过滤,但我怀疑这是不可能的,所以感谢你的建议! - CT14.IT
感谢您的编辑,很高兴听到您能够使其正常运作。 - joakimriedel
2
哇,终于有一个很好的回答了我几个小时前提出的同样问题。那个用于在映射器内部进行过滤的自定义字段就是我所需要的。谢谢! - VPetrovic

0

这个功能 过滤包含 是在EF5中引入的

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

在EF5之前,你可以像这样做

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();

对不起,我不确定你在与我遇到的问题有关的问题上提出了什么建议? - CT14.IT
据我所了解,您的过滤器不起作用。 这是因为在EF5之前,您不能在“Include”中使用过滤器。 - Svyatoslav Ryumkin
啊,我明白了,我正在使用EF5,我已经更新了问题并说明了这一点。 - CT14.IT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接