【问题标题】:Validation of nested models in view model in ASP.Net MVC在 ASP.Net MVC 中的视图模型中验证嵌套模型
【发布时间】:2013-10-03 15:02:18
【问题描述】:

我有一个使用公司模型的应用程序。 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 可以在源和目标不完全匹配的情况下工作吗?

【问题讨论】:

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


【解决方案1】:

如果您希望 automapper 能够在不明确指定映射的情况下将您的属性从模型映射到视图模型,则必须使用“扁平化约定”:意味着您必须将导航属性的名称与其属性名称连接起来.

所以你的 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 好吧,是的,您必须将您的视图模型“取消映射”到您的模型。您可以使用 automapper 执行此操作,但不会自动“展开”...
  • 啊,我认为它在两个方向上都开箱即用。感谢您对此有所了解。我继续并明确定义了我的地图(使用 ForMember 声明),现在一切正常。 +1
猜你喜欢
  • 2010-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-28
  • 1970-01-01
  • 1970-01-01
  • 2011-04-04
  • 1970-01-01
相关资源
最近更新 更多