使用 entityFramework Automapper .Net Core 的嵌套映射
Posted
技术标签:
【中文标题】使用 entityFramework Automapper .Net Core 的嵌套映射【英文标题】:Nested mapping with entityFramework Automapper .Net Core 【发布时间】:2022-01-23 21:24:15 【问题描述】:这是我对实体框架的查询:
var transportlist = await _context.Set<Transport>()
.Include(transport => transport.TransportState)
.Select(transport =>
new
Transport = _mapper.Map<TransportDto>(transport),
TransportState = _mapper.Map<TransportStateForTransportDto>(transport.TransportState),
)
.Take(limitNumber)
.ToListAsync();
return transportlist;
这是我的 TransportDto :
public class TransportDto
public int TransportId get; set;
public TransportStateForTransportDto TransportState get; set;
public bool Locked get; set;
这是我的 TransportStateForTransportDto :
public class TransportStateForTransportDto
public string Label get; set;
我希望得到类似的结果:
[
"transportId": 123456,
"transportState" :
"Label": "Deleted"
,
"locked" : false
]
但是,我有这个(这有点合乎逻辑......):
[
"transport":
"transportId": 123456,
"transportState" :
"Label": "Deleted"
,
"locked" : false
,
"transportstate":
"Label": "Deleted"
]
我想过这样做:
var transportlist = await _context.Set<Transport>()
.Include(transport => transport.TransportState)
.Select(transport =>
new
_mapper.Map<TransportDto>(transport),
)
.Take(limitNumber)
.ToListAsync();
return transportlist;
但是,如果我这样做,JSON 中的属性 transportstate 等于 NULL。
所以我正在尝试进行嵌套映射,其中 Transport 也应该映射其对象属性。请注意,所有属性的名称完全相同。
我写了一个用于映射的配置文件:
public class TransportsProfile : Profile
public TransportsProfile()
CreateMap<TransportState, TransportStateForTransportDto>();
CreateMap<Transport, TransportDto>();
提前感谢您的帮助。
【问题讨论】:
docs.automapper.org/en/latest/Queryable-Extensions.html 这不是我所期望的......事实上,在他们的例子中你不会得到我要求的 JSON 格式。此外,我不想手动分配字段,但我想全局映射 dto 以获得更灵活的代码。我如何映射到映射中? 你完全误解了。花点时间阅读文档和一些示例。 在 EF 调用中直接映射非常危险,因为 it's possible to get very deep calls (back to EF) for navigation properties 和/或通过循环递归进入无限循环。我强烈建议关闭延迟加载(如果您还没有),然后在 EF 调用之外映射您的对象。 延迟加载被禁用。那么你认为我应该首先提出我的问题吗?然后,使用获得的列表将其映射到我的 Dto 架构? 【参考方案1】:如果您使用 Automapper 8 或更高版本,则应利用 ProjectTo
而不是 Map
将实体转换为 DTO。
var transportlist = await _context.Set<Transport>()
.ProjectTo<TransportDto>(_mapper.ConfigurationProvider)
.Take(limitNumber)
.ToListAsync();
编辑:上面有 _mapper.Configuration,看起来配置是由 ConfigurationProvider 提供的。
鉴于您的 TransportDTO 包含对相关 TransportState DTO 的引用,自动映射器应该能够准确地告诉 EF 相关实体需要哪些字段,以确保正确加载它们。 Map
的问题在于,它实际上是针对加载的对象,而不是 EF 可以转换为 SQL 的表达式。
使用 Take
时,您还应该有一个 Order By 子句,以确保在超过该限制时返回的项目是可预测的。
就像使用Select
进行投影一样,无需预先加载任何相关细节或禁用延迟加载。如果您的 DTO 是纯粹的简单数据容器并且不包含对其中实体的引用,EF 将简单地编写一个查询来提取所需的字段。
【讨论】:
它有效。太棒了。谢谢你。还有一个问题是您正在使用 _mapper.Configuration。 Visual Studio 只提出 _mapper.ConfigurationProvider,反正我都在用。 是的,就是这样,如果我不在我的工作站上,我通常会从内存中提取我的答案,并且手边有一个合适的例子。 :)以上是关于使用 entityFramework Automapper .Net Core 的嵌套映射的主要内容,如果未能解决你的问题,请参考以下文章
EntityFramework监控sql和EntityFramework中的事务