EF Core 和 Automapper - 筛选 child 条记录
EF Core and Automapper - filtering child records
我想进行一个 EF Core 调用 returns a parent object 与过滤后的关联 children 列表并将其投影到 dto。我想通过 EF Core Linq 查询来执行此操作,我怀疑 ProjectTo 部分忽略了到那时为止的过滤。可能吗?
- EF 核心 5.0
- Automapper 7.0.0
我有另一个查询获取 parent 并包括所有 child 记录但没有过滤器,所以如果可能的话我想在 Dto 映射配置之外实现一些东西。
域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; }
}
查询
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"
}
]
}
什么我expect/want
请注意,我只得到一个 child 的东西而不是 2 个,这是因为一个 child 的日期在 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());
}
此功能 Filtered include 是在 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();
AFAIK Include
在您通过 Select
手动或使用 AutoMapper 投影到自定义 dto 投影时不起作用。
改为使用自定义配置文件
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();
如果不想过滤 children,只需将 upUntilDate 设置为 null(或不添加参数)。
我想进行一个 EF Core 调用 returns a parent object 与过滤后的关联 children 列表并将其投影到 dto。我想通过 EF Core Linq 查询来执行此操作,我怀疑 ProjectTo 部分忽略了到那时为止的过滤。可能吗?
- EF 核心 5.0
- Automapper 7.0.0
我有另一个查询获取 parent 并包括所有 child 记录但没有过滤器,所以如果可能的话我想在 Dto 映射配置之外实现一些东西。
域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; }
}
查询
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"
}
]
}
什么我expect/want
请注意,我只得到一个 child 的东西而不是 2 个,这是因为一个 child 的日期在 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());
}
此功能 Filtered include 是在 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();
AFAIK Include
在您通过 Select
手动或使用 AutoMapper 投影到自定义 dto 投影时不起作用。
改为使用自定义配置文件
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();
如果不想过滤 children,只需将 upUntilDate 设置为 null(或不添加参数)。