繁体   English   中英

如何使用AutoMapper创建复杂的映射?

[英]How to create complex mapping using AutoMapper?

我有以下实体模型

public class Blog 
{
    public int Id { get; set;}
    public string Title { get; set; }
    public string Body { get; set; }

    [ForeignKey("Category")]
    public int? CategoryId { get; set; }
    public virtual Category Category { get; set; }
    public virtual ICollection<Comment> Comments { get; set; }
}

public class Category
{
    public int Id { get; set;}

    public string Name { get; set; }
}

public class Comment
{
    public int Id { get; set;}

    public string Title { get; set; }
    public string Body { get; set; }
    [ForeignKey("Blog")]
    public int BlogId { get; set; }
    public virtual Blog Blog { get; set; }
}

然后,我有以下视图模型中,我想告诉AutoMapper映射Blog对象为BlogViewModel通知的CategoryName属性将需要来自Blog.Category.Name每个CommentBlog.Comments必须转换器CommentViewModel使用有机约定。

我目前在运行时使用反射为实现ICustomMap接口的任何类设置映射。 请通过Transfer(IMapper mapper)方法阅读代码中的注释。

public class BlogViewModel : ICustomMapFrom 
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Body { get; set; }
    public string MyCatName { get; set; }
    public IEnumerable<CommentViewModel> Comments { get; set; }

    // **IMPORTANT NOTE**
    // This method is called using reflection when the on Application_Start() method.
    // If IMapper is the wrong Interface to pass, I can change
    // the implementation of ICustomMap
    // I assumed that `IMapper` is what is needed to add configuration at runtime.
    public void Transfer(IConfigurationProvider config)
    {
        // How to I do the custom mapping for my MyCatName and Comments?
        // I need to use the config to create the complex mapping
        // AutoMapper.Mapper.Map(typeof(Blog), typeof(BlogViewModel));
    }
}

最后是我的CommentViewModel

public class CommentViewModel : IMapFrom<Comment>
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Body { get; set; }
}

如何告诉AutoMapper如何映射CategoryName和Comments?

更新

这是我创建映射的方式。 我将有以下3个界面

public interface IMap
{
}

public interface IMapFrom<T> : IMap
{
}

public interface ICustomMapFrom : IMap
{
    void Map(IConfigurationProvider config);
}

然后在Global.cs文件中

我会在启动时执行Run方法。 基本上,此方法将扫描程序集并使用接口注册我要注册的类。

public class ConfigureAutoMapper 
{
    public void Run()
    {
        var types = AssemblyHelpers.GetInternalAssemblies()
                                   .SelectMany(x => x.GetTypes())
                                   .Where(x => x.IsClass && !x.IsAbstract && !x.IsInterface && typeof(IMap).IsAssignableFrom(x))
                                   .ToList();


        RegisterStandardMappings(types);
        RegisterCustomMappings(types);
    }

    private static void RegisterStandardMappings(IEnumerable<Type> types)
    {
        foreach (Type type in types)
        {
            if(type.IsGenericType && typeof(IMapFrom<>).IsAssignableFrom(type))
            {
                AutoMapper.Mapper.Map(type.GetGenericArguments()[0], type);
            }
        }
    }

    private static void RegisterCustomMappings(IEnumerable<Type> types)
    {
        foreach (Type type in types)
        {
            if (typeof(ICustomMapFrom).IsAssignableFrom(type))
            {
                ICustomMapFrom map = (ICustomMapFrom)Activator.CreateInstance(type);
                var t = AutoMapper.Mapper.Configuration;

                map.Map(Mapper.Configuration);
            }
        }
    }
}

我编写了一个NUnit测试,该测试使用您的类设置了AutoMapper。 AutoMapper支持开箱即用的CategoryName映射。

[TestFixture]
public class TestClass
{
    [Test]
    public void Test1()
    {
        var config = new MapperConfiguration(cfg =>
        {
            cfg.CreateMap<Blog, BlogViewModel>();
        });

        config.AssertConfigurationIsValid();

        var blog = new Blog()
        {
            Body = "Blog body",
            Category = new Category { Name = "My Category" },
            Comments = new List<Comment>() {
                new Comment { Body = "Comment body 1" },
                new Comment { Body = "Comment body 2" }
            }
        };

        var mapper = config.CreateMapper();
        var result = mapper.Map<Blog, BlogViewModel>(blog);

        Assert.AreEqual(blog.Body, "Blog body");
        Assert.AreEqual(blog.Category.Name, result.CategoryName);
        List<CommentViewModel> comments = result.Comments.ToList();
        Assert.That(comments.Any(c => c.Body == "Comment body 1"));
        Assert.That(comments.Any(c => c.Body == "Comment body 2"));
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM