在返回使用 automapper 映射的 DTO 时,如何为它分配一个子 class 类型的列表?

While returning a DTO which is mapped using automapper, how do I assign it a list of it's child class type?

我有一个实体

Topics 具有这些属性

1. public string Name {get; set;}
2. public string Location {get; set;}
3. public string Identity {get; set;}
4. public TopicsMapped TopicsMapped {get; set;}

此外,我有一个 DTO,即 TopicsDTO,它具有属性

1. public string Name {get; set;}
2. public string Location {get; set;}
3. public string Identity {get; set;}
4. public TopicsMapped TopicsMapped {get; set;}

所以在 Automapper.config 我创建了这两个的映射。

大致上,

    var config = new MapperConfiguration(cfg => {
    cfg.CreateMap<Topics, TopicsDTO>();
    
});

现在在 webapi 方法中,我正在使用 linq to sql 并且我写了这样的东西

 var query= (from t in topics select t).tolist();

 Topics t= new topics();

 var mapper = new Mapper(config);
 var topicsDTO = mapper.Map<List<TopicsDTO>>(query);
 
 return OK(topicsDTO)  //since the webapi method returning IHttpActionResult.

但我的问题是我必须在 OK 中分配一个 TopicsMapped 类型列表和 return 作为 TOPICs DTO 的一部分。我尝试加入这两种类型并分配给查询,但它抛出了映射配置未正确配置的错误。

我该怎么做?

为您的 Web 界面定义一个 DTO 很好,但实现 DTO 的目的是提供一个特定于消费者需求的模型,并避免传递更多需要的数据,或 data/schema 信息消费者无权查看。

假设TopicsMapped 是一个包含一些字段的class,那么Topic 和TopicsMapped 之间的关系是一对一的。通常在一对一关系中,您可能希望提供来自相关实体的一些相关字段。映射 DTO 或 ViewModel 时要遵循的一般规则是不要将 DTO(视图模型)与实体混合。 (数据模型)这可能会导致问题,因为如果 TopicsMapped 引用回主题或其他 entities/tables,将该实体放入您的 DTO 可能会在序列化您的 DTO 时看到延迟加载调用或异常。在需要时为相关实体创建 DTO 图,或展平 DTO 模型以表示您关心的数据。

例如,如果 TopicsMapped 有一个我们想要包含在我们的网站中的名为“名称”的字段 API,我们不需要整个 TopicsMapped 模型,只需要该字段。所以我们可以在 DTO 中将其展平:

[Serializable]
public class TopicDTO
{
    public int TopicId { get; set; }
    public string Name { get; set; }
    public string Location { get; set; }
    public string Identity { get; set; }
    public string MappedName { get; set; } // <- Will map to TopicsMapped.Name
}

然后使用自动映射器配置:

var config = new MapperConfiguration(cfg => 
{
    cfg.CreateMap<Topics, TopicsDTO>()
        .ForMember(x => x.MappedName, opt => opt.MapFrom(src => src.TopicsMapped.Name));
};

默认情况下,Automapper 可以使用约定从源对象计算出目标字段的映射,如果您在 DTO 中遵循这些约定,则可以避免显式映射,但老实说,我更喜欢显式映射以避免如果 属性 名称被更改,猜测和错误。它还有助于确保正确计算属性的使用次数。 Linq2SQL 应该提供对 IQueryable 的访问,因此要正确利用 projection /w Automapper,您需要使用 ProjectTo 而不是 Map:

var topicDTOs = Context.Topics
    .ProjectTo<TopicDTO>(config)
    .ToList();

这将涉及为“Automapper.QueryableExtensions”添加一个 using 子句。 ProjectToMap 之间的区别在于,对于 Map,SQL 生成发生在您的 ToList 调用中。 Map 将不得不从 TopicMapping class 延迟加载数据,或者您必须将其设置为预先加载该数据。在这两种情况下,这基本上都包括来自 TopicMapping 的 all 字段,尽管在此示例中我们只需要 1 个字段。另一方面,ProjectTo 让 Automapper 进入 SQL 代。结果查询只会 return DTO 从 Topic 和 TopicMapping 表中需要的字段,仅此而已。无需急切加载相关实体,它会生成更加精简的查询。

免责声明:根据我的阅读,Linq2SQL 应该支持 IQueryable 和 Automapper 的 ProjectTo。如果您遇到问题,我强烈建议您考虑使用 Entity Framework 而不是 Linq2SQL,因为它完全支持投影、预加载和延迟加载。