如何直接在ViewModel,ID或类对象中拥有导航属性?

时间:2015-10-06 12:44:45

标签: asp.net-mvc asp.net-mvc-4

在我的MVC应用程序中,我通常ViewModel执行Edit等操作,主要用于填充要修改的属性的选择列表。例如,我的Model看起来像这样:

class MyModel{
    public int? NavPropID {get; set;}
    public AnotherModel NavProp {get; set;}
    ...
}

现在我想知道,我应该如何设计我的ViewModel来引用NavProp。

 class MyViewModel{
    public int? NavPropID {get; set;}
    public AnotherModel NavProp {get; set;}
    ...
 }

我应该同时使用NavPropIDNavProp,还是应该只使用ViewModel中的一个(?)?

我一开始只想使用NavProp,因为对我来说感觉更自然(我觉得它隐藏了数据库实现细节,而且我是如何在WPF和MVVM中做的)。但是在我的编辑视图中,我有类似的东西:

@Html.DropDownListFor(model => model.NavProp, 
                         new SelectList(Model.AllAnotherModels.Select(
                           i => new {Item = i, Text = i.Name}), "Item","Text"))

在Edit操作的回发中,我可以看到绑定器未正确绑定NavProp,因为attemptsValue的类型为string,值为NavProp的类名(我猜它意味着它使用ToString ()方法回发给控制器)​​。如何使其适用于回发行动?

然后我尝试在NavPropID中只有ViewModel。但是存在两个问题:1)这意味着我必须在使用NavPropAutoMapper映射回ViewModel之前在控制器中加载实际的Model。我觉得这超出了控制器的责任2)即使我在控制器中加载了实际的属性,我在稍后通过调用DBSet.Attach()进行更新时也遇到了一些问题。

那么ViewModel引用Model中的导航属性的最佳做法是什么?

更新: 这是我Edit动作的回发功能。它是通用的我认为所以我没有首先粘贴它。

[HttpPost]
public ActionResult Edit(MyViewModel vm)
{
   if (ModelState.IsValid)     
   {
      ... // I use Automapper to map back to Model and then 
          // use UnitOfWork and Repository to update the Model
   }
}

我的ModelState.IsValid是假的,所以无法继续。正如我所提到的,然后我检查了ModelState(字典),发现NavProp无效,attemptedValue是类名,而我认为它应该是属性的实际值。

1 个答案:

答案 0 :(得分:1)

关于在基本视图模型中使用NavPropID,我们需要确定是否适合展平您的视图模型。

如果视图模型适用于显示单个导航属性的页面。信息,我很想得到以下信息:

// Domain model
public class MyModel
{
    public int? NavPropID { get; set; }
    public NavProp NavProp { get; set; }
    ...
}

// Nav prop domain model
public class NavProp
{
    public int? NavPropID { get; set; }

    // Another property of your navigation property
    public string AnotherProperty { get; set; }
}

// Flat view model containing all your navigation properties' properties
public class MyViewModel
{
    public int? NavPropID { get; set; }
    public string AnotherProperty { get; set; }
}

如果你想要,你可以引入另一个视图模型来表示你的NavProp项目 - 但如果你乐意将它弄平,那就太过分了:

// Domain model
public class MyModel
{
    public int? NavPropID {get; set;}
    public NavProp NavProp {get; set;}
    ...
}

// Nav prop domain model
public class NavProp
{
    public int? NavPropID {get; set;}

    // Another property of your navigation property
    public string AnotherPropery {get; set;}
}

// View model representing your navigation property
public class NavPropViewModel 
{
    public int? NavPropID { get; set; }
    public string AnotherProperty { get; set; }
}

// Main view model
public class MyViewModel
{
    // Use another view model that represents your NavProp
    public NavPropViewModel NavProp { get; set; }
    ...
}

我想说控制器无需将从业务层收到的对象映射到视图模型,反之亦然。

为了使这个更清洁,我会介绍DTO来映射到哪个可以传递到您的业务层。 Check out general comments on this post.

<强>更新

以下是如何使用MyViewModel字段创建表单以回发到NavPropViewModel

示例视图:

@model MyViewModel
@using (Html.BeginForm())
{
    @Html.LabelFor(x => x.NavProp.AnotherProperty)
    @Html.TextBoxFor(x => x.NavProp.AnotherProperty)
}

控制器示例:

[HttpPost]
public ActionResult Edit(MyViewModel vm)
{
    // Get the posted value of AnotherProperty
    var postedValue = vm.NavProp.AnotherProperty;
}