0

我有以下实体模型

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通知中,并且每个都需要转换为使用有机约定。CategoryNameBlog.Category.NameCommentBlog.CommentsCommentViewModel

我目前在运行时使用反射为任何实现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);
            }
        }
    }
}
4

1 回答 1

0

我写了一个 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"));
    }
}
于 2018-03-02T02:45:31.970 回答