我有一个公司模型的应用程序. Company模型具有Address模型的导航属性(一对一关系):
Company.cs
public class Company
{
public int CompanyID { get; set; }
public string Name { get; set; }
// Snip...
public virtual Address Address { get; set; }
}
我创建了一个视图模型来处理编辑,细节和创建操作:
CompanyViewModel.cs
public class CompanyViewModel
{
public int CompanyID { get; set; }
[Required]
[StringLength(75, ErrorMessage = "Company Name cannot exceed 75 characters")]
public string Name { get; set; }
// Snip...
public Address Address { get; set; }
}
我在我的控制器中使用AutoMapper在模型和视图模型之间来回映射,一切正常.但是,我现在想在地址对象上使用验证 – 我不希望在没有地址存在的情况下创建公司.
我的第一个想法是简单的路线 – 我尝试在Address属性上添加'[Required]’注释.这没有做任何事情.
然后我认为最好不要使用Address属性并在视图模型中抽象该数据,因此我在Address类的所有属性的视图模型中添加了属性:
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
// etc....
这似乎是一种很好的做法,但现在我的AutoMapper无法将这些属性映射到Company类的Address对象,因此我不得不在控制器中手动映射:
public ActionResult Details(int id = 0)
{
// Snip code retrieving company from DB
CompanyViewModel viewModel = new CompanyViewModel();
viewModel.Name = company.Name;
viewModel.Address1 = company.Address.Address1;
// Snip...
return View(viewModel);
}
这导致我的控制器中有很多额外的代码,而不是一个漂亮的单行AutoMapper语句……那么处理这个问题的正确方法是什么(在视图模型中验证嵌套模型)?
在视图模型中直接公开Address属性是一种好习惯,还是更好地使用像我一样的单独属性将其抽象出来?
AutoMapper可以在源和目标不完全匹配的情况下工作吗?
最佳答案 如果您希望automapper能够将您的属性从model映射到viewmodel而不明确指定映射,则必须使用“flattenting约定”:意味着必须将导航属性的名称与其属性名称连接起来.
所以你的ViewModel应该包含
public int CompanyID { get; set; }
[Required]
[StringLength(75, ErrorMessage = "Company Name cannot exceed 75 characters")]
public string Name { get; set; }
// Snip...
//Address is the navigation property in Company, Address1 is the desired property from Address
public string AddressAddress1 { get; set; }
public string AddressAddress2 { get; set; }
public string AddressCity { get; set; }
public string AddressPostalCode { get; set; }
}
顺便说一句,您还可以告诉AutoMapper映射不明确遵循命名约定的属性:
Mapper.CreateMap<Company, CompanyViewModel>()
.ForMember(dest => dest.Address1, opt => opt.MapFrom(src => src.Address.Address1));