c# - 如何使用 AutoMapper 将 Dto 映射到具有嵌套对象的现有对象实例?

标签 c# .net nested automapper dto

我有以下 Dto 和带有嵌套子实体的实体。

public class Dto
{
    public string Property { get; set; }
    public string SubProperty { get; set; }
}

public class Entity
{
    public string Property { get; set; }
    public SubEntity Sub { get; set; }
}

public class SubEntity
{
    public string SubProperty { get; set; }
}

如何使用 AutoMapper 设置一个映射,使我可以使用 Dto 中的值更新 Entity 的现有实例.

我正在使用 Mapper.Map(dto, entity) 来更新现有实体,但是当我尝试将 Dto.SubProperty 映射到 Entity.Sub 时.SubProperty 我得到一个异常 “必须解析为顶级成员。参数名称:lambdaExpression”

如果我使用 FromMember 创建从 DtoSubEntity 的映射,则 Entity.Sub 会被替换为SubEntity 的新实例,但这不是我想要的。我只希望它在 EntitySub 属性上更新 SubEntity 的现有实例的属性。

我怎样才能做到这一点?

最佳答案

我通过结合使用 ResolveUsing<T>() 解决了这个问题方法与实现IValueResolverConvertUsing<T>()方法与实现ITypeConverter<TSource,TDestination> .

我的一些映射场景比正常情况更复杂,包括双向映射和嵌套类以及嵌套集合。以上帮助我解决了这些问题。


编辑

根据要求,我提供了一个示例解决方案。这个示例比我处理的实际类型简单得多。

using System;
using AutoMapper;

namespace TestAutoMapperComplex
{
    public class Dto
    {
        public string Property { get; set; }
        public string SubProperty { get; set; }
    }

    public class Entity
    {
        public string Property { get; set; }
        public SubEntity Sub { get; set; }
    }

    public class SubEntity
    {
        public string SubProperty { get; set; }
    }

    static class MapperConfig
    {
        public static void Initialize()
        {
            Mapper.CreateMap<Dto, Entity>()
                .ForMember(entity => entity.Sub, memberOptions =>
                    memberOptions.MapFrom(dto => dto));
            Mapper.CreateMap<Dto, SubEntity>();
        }
    }

    static class MapperConfig2
    {
        private class MyResolver : IValueResolver
        {

            public ResolutionResult Resolve(ResolutionResult source)
            {
                var destinationSubEntity = ((Entity)source.Context.DestinationValue).Sub;

                Mapper.Map((Dto)source.Value, destinationSubEntity);

                return source.New(destinationSubEntity, typeof(SubEntity));
            }
        }

        public static void Initialize()
        {
            Mapper.CreateMap<Dto, Entity>()
                .ForMember(entity => entity.Sub, memberOptions =>
                    memberOptions.ResolveUsing<MyResolver>());
            Mapper.CreateMap<Dto, SubEntity>();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MapperConfig.Initialize();

            var dto = new Dto {Property = "Hello", SubProperty = "World"};
            var subEntity = new SubEntity {SubProperty = "Universe"};
            var entity = new Entity {Property = "Good bye", Sub = subEntity};

            Mapper.Map(dto, entity);

            Console.WriteLine(string.Format("entity.Property == {0}, entity.Sub.SubProperty == {1}",
                entity.Property, entity.Sub.SubProperty));
            Console.WriteLine(string.Format("entity.Sub == subEntity: {0}", 
                entity.Sub == subEntity));

        }
    }
}

如果您运行示例,它使用 MapperConfig ,您将获得以下输出:

entity.Property == Hello, entity.Sub.SubProperty == World
entity.Sub == subEntity: False

字符串属性都按预期更新,但是 entity.SubSubEntity 的新实例替换当您想要更新将持久保存到数据库的 ORM 实体时,这并不适用。

如果修改Main这样MapperConfig2被改用,你仍然会像以前一样更新字符串属性,但是entity.sub仍然有相同的 SubEntity 实例它以前有过。使用 MapperConfig2 运行示例给出这个输出:

entity.Property == Hello, entity.Sub.SubProperty == World
entity.Sub == subEntity: True

MapperConfig2 的关键区别是那个ResolveUsingMyResolver 一起使用保留 entity.Sub 的值(value).

关于c# - 如何使用 AutoMapper 将 Dto 映射到具有嵌套对象的现有对象实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3672447/

相关文章:

.net - 如何在客户端拦截 WCF 错误

performance - 如何对嵌套的Sybase存储过程进行性能测试?

c# - 检查对象是否可以转换为特定值类型?

c# - 如何轻松地将两个异步请求链接在一起?

c# - 从 XML、XSD 或 C# 类生成 LINQ DataContext

.net - 当页面未处于编辑模式时检查用户是否具有模块编辑权限

C++动态嵌套for循环

按嵌套类型数组中的第一个元素排序

c# - Entity Framework 4 - 如何使用联接表 C# 插入记录

c# - 如何在 Windows Phone 7 上将 JSON 解析为动态对象?