AutoMapper Complex ViewModel属性

时间:2012-06-10 19:52:01

标签: c# asp.net-mvc-3 automapper

我希望你能够帮助我解决我正在开发的测试ASP.NET MVC应用程序中的Automapper问题。

我已经浏览了一下,我找不到任何类似于我想用嵌套的ViewModel实现的东西。

基本上,我有这两个域模型......

namespace Test.Domain.Entities
{
    public class Contact
    {
        [HiddenInput(DisplayValue = false)]
        [Key]
        public int ID { get; set; }

        public Name Name { get; set; }

        public string Contact_Landline { get; set; }

        public string Contact_Mobile { get; set; }

        [DataType(DataType.EmailAddress)]
        public string Contact_Email { get; set; }
    }
}

和..

namespace Test.Domain.Entities
{
    public class Name : DisplayableModel
    {
        [HiddenInput(DisplayValue = false)]
        [Key]
        public int ID { get; set; }

        public string Name_Forename { get; set; }

        public string Name_Surname { get; set; }

        public string GetFullName()
        {
            return Name_Forename + ' ' + Name_Surname;
        }
    }
}

我有这两个ViewModels ......

namespace Test.WebUI.Models
{
    public class ContactViewModel :
    {
        [HiddenInput(DisplayValue = false)]
        [Key]
        public int ID { get; set; }

        public NameViewModel Name { get; set; }

        public string Contact_Landline { get; set; }

        public string Contact_Mobile { get; set; }

        [DataType(DataType.EmailAddress)]
        public string Contact_Email { get; set; }
    }
}

和...

namespace Test.WebUI.Models
{
    public class NameViewModel 
    {
        [HiddenInput(DisplayValue = false)]
        [Key]
        public int ID { get; set; }

        public string Name_Forename { get; set; }

        public string Name_Surname { get; set; }
    }
}

我想将ContactViewModel返回到我的View,其Name属性填充了填充Contact域对象的Name属性。

我的控制器中有这个代码......

Mapper.CreateMap<Name, NameViewModel>();
Mapper.CreateMap<Contact, ContactViewModel>();
var contact = Mapper.Map<Contact, ContactViewModel>(repository.Contact.Where(c => c.ID == id).Single()); 
return View(contact);

这是我遇到问题的地方,我的名字属性从未填充过。

我选择以这种方式设计我的应用程序的原因是因为我的视图由自定义模型模板组成,因此我可以一致地呈现NameViewModel对象而不重复代码,就像在这个简单的例子中一样......

@model Test.WebUI.Models.NameViewModel

First
@Model.Name_Forename
Last
@Model.Name_Surname

如果有人可以帮我解释如何用AutoMapper填充ContactViewModel的NameViewModel对象,我真的很感激。

感谢。 吉姆

2 个答案:

答案 0 :(得分:1)

这应该是开箱即用的,如下所示:

public class Name 
{
    [HiddenInput(DisplayValue = false)]
    [Key]
    public int ID { get; set; }

    public string Name_Forename { get; set; }

    public string Name_Surname { get; set; }

    public string GetFullName()
    {
        return Name_Forename + ' ' + Name_Surname;
    }
}


public class Contact
{
    public int ID { get; set; }

    public Name Name { get; set; }

    public string Contact_Landline { get; set; }

    public string Contact_Mobile { get; set; }

    public string Contact_Email { get; set; }
}

public class NameViewModel
{
    [HiddenInput(DisplayValue = false)]
    [Key]
    public int ID { get; set; }

    public string Name_Forename { get; set; }

    public string Name_Surname { get; set; }

}

public class ContactViewModel
{
    [HiddenInput(DisplayValue = false)]
    [Key]
    public int ID { get; set; }

    public NameViewModel Name { get; set; }

    public string Contact_Landline { get; set; }

    public string Contact_Mobile { get; set; }

    [DataType(DataType.EmailAddress)]
    public string Contact_Email { get; set; }
}


class Program
{
    static void Main()
    {
        Mapper.CreateMap<Name, NameViewModel>();
        Mapper.CreateMap<Contact, ContactViewModel>();

        var contact = new Contact
        {
            Name = new Name
            {
                Name_Forename = "forename"
            }
        };
        var vm = Mapper.Map<Contact, ContactViewModel>(contact);
        Console.WriteLine(vm.Name.Name_Forename);
    }
}

按预期打印:

forename

因此,请确保repository.Contact.Where(c => c.ID == id).Single()调用返回Contact实例,其Name属性已正确实例化并包含其属性值。

现在,这就是说,您的代码存在一些问题:

  • 您使用[HiddenInput]属性修饰了域模型属性,该属性是视图特定的内容,属于您的视图模型。
  • 您已使用[Key]属性修饰了视图模型属性。这是数据访问特定的东西,视图模型应该是不可知的。
  • 您正在控制器操作中调用Mapper.CreateMap<TSource, TDest>方法。这是错的。映射定义应仅在应用程序域的整个生命周期内完成一次。这通常发生在名为Application_Start内部的辅助方法中,以确保您的映射定义只执行一次。在控制器操作中,您应该只使用Mapper.Map<TSource, TDest>方法来执行实际映射。

答案 1 :(得分:0)

如前所述,您应该只定义一次映射(在APP_Start文件夹中) 不确定这是否正是您所需要的,但您可以通过以下方式进行映射:

Mapper.CreateMap<Contact, ContactViewModel>()
.ForMember(c => c.Name, opt => opt.MapFrom(o => o.Name_Forename + " " + o.Name.Lastname);