使用 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 的嵌套映射的主要内容,如果未能解决你的问题,请参考以下文章

Web 自动化神器,批量下载美图,可直接导入使用

EntityFramework监控sql和EntityFramework中的事务

使用NuGet安装EntityFramework4.2

EntityFramework和EntityFramework.Extended使用说明——性能,语法和产生的sql

EntityFramework优缺点

EntityFramework中支持BulkInsert扩展