Asp.net mvc 4 MVC通过数据预填充将模型传回控制器

Asp.net mvc 4 MVC通过数据预填充将模型传回控制器,asp.net-mvc-4,model,controller,sql-update,Asp.net Mvc 4,Model,Controller,Sql Update,我现在已经多次遇到这个问题。我用不同的方法解决了这个问题,但总觉得有更好的方法来处理这个问题。寻找解决方案(最佳实践)产生了nada。希望得到一些明智的建议 场景是这样的:我正在构建一个MVC4 web应用程序。我正在向我的视图传递一个复杂的模型。例如: public class Uat { public int UatId { get; set; } public int ProjectId { get; set; } public virtual Project P

我现在已经多次遇到这个问题。我用不同的方法解决了这个问题,但总觉得有更好的方法来处理这个问题。寻找解决方案(最佳实践)产生了nada。希望得到一些明智的建议

场景是这样的:我正在构建一个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; }
}
问题是,控制器中我的uat对象只有TestCases数据。其他所有内容均为null或0。Uat中的测试用例只有注释和状态数据,其他所有数据都为null或0。因此,如果我尝试在此模型上运行更新,我会得到错误:ObjectStateManager中已经存在具有相同键的对象。我已经调查过了,这对我来说很有意义。但为了纠正这一点,我在过去做了两件事中的一件:

  • 我在视图中创建了一组隐藏字段来填充模型中的其余属性,这样当模型被传递回控制器时,所有数据都以与我从数据库中提取数据时相同的方式填充;除非它有用户所做的更改

  • 我从数据库中重新提取TestCase条目,对该条目进行适当的更改,然后保存更改()


  • 这两种解决方案对我来说都很难看,而且我肯定我做得不对。虽然这在过去为我解决了这个问题,但它会导致我的视图被隐藏的字段弄得乱七八糟,或者我最终向数据库发出了太多的请求。我的应用程序很小,所以这些变通方法现在没有多大效果,但我真的想养成最佳实践的习惯。任何来自SO社区的帮助都将不胜感激。提前谢谢

    这就是为什么需要一个表示实体全部或部分的viewmodel。使用viewmodel的好处之一是可以防止过重或过少过帐。你的情况就是一个很好的例子。您只需要更新实体的几个字段,这在大多数情况下是有意义的,因此不需要将其余字段返回到视图。甚至没有将它们作为隐藏字段,只是为了将值发回并保存在数据库中。如果只需要其中两个字段,则为其创建一个模型,如:

    public class TestCaseModel
    {
        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;
    
    由于您将选择viewmodel路线,因此您可能需要为您的
    Uat
    实体创建一个viewmodel。或者最好的方法是使用一个扁平的模型,如下所示:

     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; }
    }
    
    @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" />
    }
    
        [HttpPost]
        public ActionResult UatEvalution(Uat uat)
        {
            //process data
            //Update(uat);
            //SaveChanges();
        }
    
        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; }
        }
    
    然后只需添加必要的字段或您希望“显示”的字段,这意味着您不希望有输入。然后必须将模型的所有“输入”字段映射回实体。比如:

    public class TestCaseModel
    {
        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;
    

    此外,可以使用自动映射工具将值从模型返回到实体。这是你能做到的最干净的方法,我想。

    谢谢你的解释。ViewModels在过去帮助过我。有时候,我觉得我必须破解一些东西,而实际上,我想这就是mvc的工作方式。我感谢你的反馈!不客气。我希望您在当前的项目@nycfdtd中也选择viewmodels。