【问题标题】:Automapper Composite DTO to ViewModel conversionAutomapper Composite DTO 到 ViewModel 的转换
【发布时间】:2012-04-30 20:09:32
【问题描述】:

在某些情况下,需要从我们的存储库中返回复合 DTO,其中 DTO 仅具有一些模型属性,并且 DTO 的功能只是一个简单的复合对象(返回 Queryable 不是足够了,因为信息比T多)

例如:

型号:

public class Job
{
    int Id { get; set; }
    //more properties
}

public class JobApplication
{
    int Id { get; set; }
    //more properties
}

存储库: IQueryable<JobAndUserApplication> GetJobAndMatchingUserApplication(int userId):

public class JobAndUserApplication
{
    public Job Job { get; set; }
    public JobApplication JobApplication { get; set; }
}

现在 - 我想简单地做(Project 和 To 是 Automapper 功能):

//this allows one efficient query to bring in the subproperties of the composite DTO    
var jobVmList = jobRepository.GetAllJobsAndMatchingJobApplicationByUser(userId)              
                             .Project()
                             .To<JobVM>()
                             .ToList();

所以我需要一个类似这样的映射:

Mapper.CreateMap<JobAndUserApplication, JobVM>()
      .ForMember(jvm => jvm, opt => opt.ResolveUsing(src => src.Job));
      //many other .ForMembers that are not relevant right now

我正在尝试将 DTO 的 Job 属性直接映射到 JobVM(共享许多相同的属性)。

我的映射引发以下异常:

成员的自定义配置仅支持类型上的顶级个人成员。

我做错了什么,如何在 JobVM 本身上完成 DTO 的 Job 属性的映射?

谢谢

【问题讨论】:

    标签: c# automapper


    【解决方案1】:

    Automapper 告诉您,您只能在类的成员(属性)上定义自定义操作,而不是在类本身上。你需要做的是首先创建一个 Job 到 JobVM 的映射:

    Mapper.CreateMap<Job, JobVM>()
    

    Mapper.CreateMap<JobAndUserApplication, JobVM>()
    

    确保忽略并设置这两种类型的任何重复属性。然后运行 ​​automapper 两次,首先从子对象:

    var jobVM = Mapper.Map<Job, JobVM>(jobAndUserApplication.job);
    

    然后从父对象

    Mapper.Map<JobAndUserApplication, JobVM>(jobAndUserApplication, jobVM );
    

    或反过来,取决于您的属性的布局方式。

    快速旁注:我感觉您可能会混淆问题,并且我的代码异味警报正在响起。我会再看一下您的视图模型或域模型,因为这不是我看到的典型问题。 (只是我的 0.02 美元 :-)

    【讨论】:

    • 谢谢杰森。我试图避免两次调用 Map 方法——这并不是什么大不了的事,但我认为 AutoMapper 及其丰富的配置应该能够让我配置映射,这样我只需要调用一次 Map。我将在不同的评论中回复代码异味。
    • 我们的存储库只返回模型,我们的服务层在存储库上运行并返回 DTO。在服务中调用多个存储库方法以将返回的结果粘合在一起是一个不必要的性能问题(数据库可以很好地执行多个查询和不必要的内存处理)。除了使用复合类(仅将两个模型粘合在一起)来返回模型以运行不必在内存处理中执行的单个选择高效查询之外,我没有其他方法。这是因为 AFAIK Automapper 无法处理匿名类型。
    • 嗯,有道理。您可以采取的另一种方法是在 .AfterMap() 中设置自定义映射逻辑,您可以使用匿名函数来定义自定义映射逻辑,这可以帮助您避免第二次调用。
    • 谢谢 Jason - 我已经尝试了所有这些,但它们都不起作用:-.AfterMap((jaua, jvm) =&gt; { Mapper.Map&lt;Job, JobVM&gt;(jaua.Job, jvm);}); -.ConstructUsing(jaua =&gt; { Mapper.CreateMap&lt;Job, JobVM&gt;(); return Mapper.Map&lt;Job, JobVM&gt;(jaua.Job); }); -.ConvertUsing( jaua =&gt; {return Mapper.Map&lt;Job, JobVM&gt;(jaua.Job, new JobVM()); }); -.ForMember(jvm =&gt; jvm, opt =&gt; opt.ResolveUsing(src =&gt; src.Job));
    • 我上传了几个月前创建的自动映射 POC。也许您可以分叉它并在其中详细说明您遇到的问题?我的猜测是缺少一些我在问题中没有看到的东西。 github.com/JasonMore/AutoMapper-Ioc-Example
    猜你喜欢
    • 2013-06-08
    • 2021-11-18
    • 1970-01-01
    • 2012-08-06
    • 2021-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多