【问题标题】:EF Core and Automapper - filtering child recordsEF Core 和 Automapper - 过滤子记录
【发布时间】:2021-03-01 09:04:28
【问题描述】:

我想进行一个 EF Core 调用,该调用返回一个父对象,该对象具有过滤后的关联子项列表,并将其投影到 dto。我想通过 EF Core Linq 查询来做到这一点,我怀疑 ProjectTo 部分忽略了到目前为止的过滤。有可能吗?

  • EF Core 5.0
  • 自动映射器 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"
    }
  ]
}

我期望/想要什么

请注意,我只得到一个孩子的东西而不是 2 个,这是因为一个孩子的日期在 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&lt;T&gt; 仅执行以下操作

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

【问题讨论】:

  • 您始终可以在 AM 配置中编写过滤器,然后您就不需要 Include,它通常使用 ProjectTo 的方式。
  • 感谢@LucianBargaoanu 我已将问题编辑得更清楚;有时我想在不应用过滤器的情况下获取父记录,并且能够为每个查询共享 Dto 对象。希望这是可能的,但我不确定。

标签: c# entity-framework .net-core entity-framework-core automapper


【解决方案1】:

当您通过 Select 手动或使用 AutoMapper 投影到自定义 dto 投影时,AFAIK 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 时可以使用。理想情况下,我想避免在映射中进行过滤,但我怀疑这是不可能的,所以感谢您的输入!
  • 感谢您的编辑,很高兴听到您能成功。
  • 哇,终于为我几个小时以来的同一个问题找到了一个很好的答案。我只需要在映射器中过滤的自定义字段。谢谢!
【解决方案2】:

此功能Filtered include 是在 EF5 中引入的

.Include(x => x.ChildThings.Where(y => y.Date

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

【讨论】:

  • 抱歉,对于我遇到的问题,我不确定您的建议是什么?
  • 据我了解,您的过滤器不起作用。那是因为你不能在EF5之前的Include中使用过滤器
  • 啊,我明白了,我正在运行 EF5,我已经更新了说明这一点的问题
猜你喜欢
  • 2021-12-06
  • 1970-01-01
  • 2020-11-27
  • 2021-04-21
  • 2020-01-09
  • 1970-01-01
  • 1970-01-01
  • 2021-12-26
  • 1970-01-01
相关资源
最近更新 更多