在返回使用 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
子句。 ProjectTo
和 Map
之间的区别在于,对于 Map
,SQL 生成发生在您的 ToList
调用中。 Map
将不得不从 TopicMapping class 延迟加载数据,或者您必须将其设置为预先加载该数据。在这两种情况下,这基本上都包括来自 TopicMapping 的 all 字段,尽管在此示例中我们只需要 1 个字段。另一方面,ProjectTo
让 Automapper 进入 SQL 代。结果查询只会 return DTO 从 Topic 和 TopicMapping 表中需要的字段,仅此而已。无需急切加载相关实体,它会生成更加精简的查询。
免责声明:根据我的阅读,Linq2SQL 应该支持 IQueryable
和 Automapper 的 ProjectTo
。如果您遇到问题,我强烈建议您考虑使用 Entity Framework 而不是 Linq2SQL,因为它完全支持投影、预加载和延迟加载。
我有一个实体
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
子句。 ProjectTo
和 Map
之间的区别在于,对于 Map
,SQL 生成发生在您的 ToList
调用中。 Map
将不得不从 TopicMapping class 延迟加载数据,或者您必须将其设置为预先加载该数据。在这两种情况下,这基本上都包括来自 TopicMapping 的 all 字段,尽管在此示例中我们只需要 1 个字段。另一方面,ProjectTo
让 Automapper 进入 SQL 代。结果查询只会 return DTO 从 Topic 和 TopicMapping 表中需要的字段,仅此而已。无需急切加载相关实体,它会生成更加精简的查询。
免责声明:根据我的阅读,Linq2SQL 应该支持 IQueryable
和 Automapper 的 ProjectTo
。如果您遇到问题,我强烈建议您考虑使用 Entity Framework 而不是 Linq2SQL,因为它完全支持投影、预加载和延迟加载。