【问题标题】:Nested mapping with entityFramework Automapper .Net Core使用 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>();
        }
    }

提前感谢您的帮助。

【问题讨论】:

  • 这不是我所期望的......事实上,在他们的例子中你不会得到我要求的 JSON 格式。此外,我不想手动分配字段,但我想全局映射 dto 以获得更灵活的代码。我如何映射到映射中?
  • 你完全误解了。花点时间阅读文档和一些示例。
  • 在 EF 调用中直接映射非常危险,因为 it's possible to get very deep calls (back to EF) for navigation properties 和/或通过循环递归进入无限循环。我强烈建议关闭延迟加载(如果您还没有),然后在 EF 调用之外映射您的对象。
  • 延迟加载被禁用。那么你认为我应该首先提出我的问题吗?然后,使用获得的列表将其映射到我的 Dto 架构?

标签: entity-framework .net-core automapper 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,反正我都在用。
  • 是的,就是这样,如果我不在我的工作站上,我通常会从内存中提取我的答案,并且手边有一个合适的例子。 :)
猜你喜欢
  • 1970-01-01
  • 2020-07-17
  • 1970-01-01
  • 2020-12-12
  • 1970-01-01
  • 2017-07-20
  • 2020-02-04
  • 1970-01-01
相关资源
最近更新 更多