AutoMapper复杂视图模型属性

本文关键字:属性 模型 视图 复杂 AutoMapper | 更新日期: 2023-09-27 18:36:39

我希望你能帮我解决我在ASP测试中遇到的一个Automapper问题。NET MVC应用程序。

我环顾四周,找不到任何与我试图使用嵌套ViewModels实现的目标类似的东西。

基本上,我有这2个领域模型…

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;
        }
    }
}

我有这两个ViewModel…

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返回到我的视图,其中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);

这就是我遇到问题的地方,我的Name属性从未被填充。

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

@model Test.WebUI.Models.NameViewModel
First
@Model.Name_Forename
Last
@Model.Name_Surname

如果有人能帮我解释我应该如何用AutoMapper填充ContactViewModel的NameViewModel对象,我将不胜感激。

谢谢。Jim

AutoMapper复杂视图模型属性

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

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>方法来执行实际映射

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

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