2013-04-03 41 views
1

我已经多次遇到此问题。我以不同的方式解决了这个问题,但总觉得有更好的方法来处理这种情况。寻找解决方案(最佳实践)已经取得了胜利。希望得到一些圣人的建议。MVC传递模型返回控制器,预填充数据

这种情况是这样的:我正在构建一个MVC4 web应用程序。我将一个复杂的模型传递给我的观点。例如:

public class Uat 
{ 
    public int UatId { get; set; } 
    public int ProjectId { get; set; } 
    public virtual Project Project { get; set; } 
    public virtual ICollection<TestCase> TestCases { get; set; } 
    public UatStatus Status { get; set; } 
    public string StartDate { get; set; } 
    public string StatusChangeDate { get; set; } 
    public string ProductVersion { get; set; } 
    public string Introduction { get; set; } 
    public bool isActive { get; set; } 
} 

我想将此模型传递给视图并让用户仅更新模型的某些部分。在我正在处理的当前实例中,用户正在更新子对象(TestCase)的两个字段。 TestCase对象如下所示:

public class TestCase 
{ 
    [Key] 
    public int TestCaseId { get; set; } 
    public int UatId { get; set; } 
    public virtual Uat Uat { get; set; } 
    public virtual ICollection<Step> Steps { get; set; } 
    public TestCaseStatus Status { get; set; } 
    public string Title { get; set; } 
    public string Comment { get; set; } 
} 

用户只编辑TestCase.Comment和TestCase.Status。大部分其他值已经由管理员用户设置。所以我通过用户验收测试对象,以我的观点,看起来像这样:

@Model ClientPortal.Models.Uat 

@{ 
ViewBag.Title = "Uat"; 
} 

<h2>Uat</h2> 

@using (Html.BeginForm("UatEvalution", "Client")) 
{ 
@Html.ValidationSummary(true) 
<div> 
    @{var iteration = 0;} 
    @foreach (var testCase in Model.TestCases) 
    { 
     <div class="well"> 
     <span class="testCaseTitle"><h4>@testCase.Title</h4></span> 

     <br /> 
     <br /> 

     <ol style="margin-left:40px"> 
      @foreach (var step in testCase.Steps) 
      { 
       <li>@step.Description</li> 
      } 
     </ol> 

     <br /> 

     <input type="checkbox" name="TestCases[@iteration].Status" value="2" />Approve &nbsp; &nbsp; 
     <input type="checkbox" name="TestCases[@iteration].Status" value="1" />Deny 

     <br /> 

     <span><textarea name="TestCases[@iteration].Comment"></textarea></span> 


     @{iteration = iteration + 1; 
    } 
     </div> 
    } 
</div> 
<input type="submit" /> 
} 

我controllerAction看起来是这样的:

[HttpPost] 
    public ActionResult UatEvalution(Uat uat) 
    { 
     //process data 
     //Update(uat); 
     //SaveChanges(); 
    } 

的问题是,在控制器我UAT对象只具有的TestCases数据。其他所有内容都为null或0. Uat中的TestCases只有注释和状态的数据,其他的都是null或0.因此,如果我尝试在此模型上运行更新,则会出现以下错误:具有相同密钥的对象已经存在于ObjectStateManager中。我研究过这个,这对我很有意义。但要解决这个问题,我已经做了在过去的两两件事之一:

  1. 我在视图中创建一批隐藏字段来填充模型属性的其余部分,这样,当模型传回给Controller,所有的数据都以我从数据库中取出时的相同方式填充;除了它有用户所做的更改。

  2. 我重新从数据库中拉出TestCase条目,对该条目进行适当的修改,然后对SaveChanges()进行相应的修改。

这两种解决方案对我来说都很难看,而且我确信我做的不正确。虽然这在过去为我解决了这个问题,但这会导致我的视​​图混淆隐藏的字段,或者最终向db提出太多请求。我的应用程序很小,因此这些解决方法现在没有太大影响,但我确实想要养成最佳做法的习惯。任何帮助将不胜感激,因为它始终来自SO社区。提前致谢!

回答

2

这就是为什么您需要一个视图模型来表示全部或部分实体。使用视图模型的好处之一是防止过度或不足。你的情况就是一个很好的例子。您只需更新实体的几个字段,实际上大部分时间是有意义的,因此您无需将其余字段返回给视图。甚至没有将它们作为隐藏字段,只是为了将值重新发布并保存在数据库中。如果你只需要其中两个字段然后创建一个模型,它是这样的:

public class TestCaseModel 
{ 
    public int TestCaseId { get; set; } 
    public TestCaseStatus Status { get; set; } 
    public string Comment { get; set; } 
} 

既然你将去的视图模型的路线,你可能也需要有一个视图模型为您Uat实体。或者,最好的办法是有一个模式是这样的:

public class TestCaseInputModel 
    { 
     public int UatId{ get; set; } // for reference 
     public int TestCaseId { get; set; } 
     public TestCaseStatus Status { get; set; } 
     public string Comment { get; set; } 
    } 

然后,只需添加必要的字段或要“秀”这些领域,这意味着你不希望有投入。然后您必须将模型的所有“输入”字段映射回您的实体。例如:

var testCaseEntity = retrieve_from_db(); 
testCaseEntity.UatId = input.UatId; 
testCaseEntity.Status = input.Status; 
testCaseEntity.Comment = input.Comment; 

此外,您可以使用自动映射工具将模型中的值返回给实体。这是你可以做到的最干净的方式,海事组织。

+0

谢谢您对von的解释。 ViewModels在过去帮助过我。有时候我觉得我不得不破解一些东西,但实际上我猜这只是mvc的工作原理。感谢您的反馈! – nycfdtd

+0

不客气。我希望你选择在当前的项目@nycfdtd中也有viewmodels。 –

相关问题