ASP.Net MVC中视图模型中嵌套模型的验证

4
我可以帮您翻译成简体中文:

我有一个应用程序,其中包含一个公司模型。公司模型与地址模型具有导航属性(一对一关系):

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能够工作吗?

请查看此问题:http://stackoverflow.com/questions/3334781/asp-net-mvc-2-validate-nested-objects - Slavo
1个回答

2
如果您希望Automapper能够在不明确指定映射关系的情况下从模型映射到ViewModel中的属性,您必须使用“扁平化规则”:这意味着您必须将导航属性名称与其属性名称连接起来。因此,您的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));

这似乎是我需要的...我按照指定更改了我的属性名称(AddressAddress1,AddressAddress2等...) - 这适用于读取客户数据,但当我编辑并保存时,我的更改未被应用。我没有收到任何错误或其他信息,我只是失去了对地址所做的更改(对公司名称的更改等仍然正常工作)...有什么想法吗? - Jim
进一步的测试显示,当显示信息时(公司地址被显示)和删除公司时(相关地址被删除),映射起作用...但是当我编辑地址时,没有任何更改被保存,当我创建一个新公司时,它是没有地址的...我需要以某种方式更改我的控制器保存方法吗? - Jim
1
@Jim 嗯,是的,你需要将你的viewModel映射到你的model上。你可以使用automapper来完成这个过程,但是你不会自动得到“展开”的效果... - Raphaël Althaus
啊,我以为它可以直接双向工作。感谢你的解释。我已经明确定义了我的映射(使用 ForMember 声明),现在一切都正常了。+1 - Jim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接