2014-07-14 22 views
-1

我有一个问题,当我的剃刀视图没有提供更新的模型对象到控制器时,表单发布到控制器进行更新。剃刀视图不会发布更新后的模型数据到控制器 - 数据绑定失败

该视图旨在允许用户对现有记录进行更改并将其保存回数据库。多个可更新记录使用'@foreach'显示在表单上。

控制器向视图(GET)提供了正确的数据,但无论我尝试什么,每次POST返回或“保存”数据时,返回给控制器的对象都是原始对象。当用户返回控制器保存更新时,用户在视图中所做的任何更改都不会反映到对象中。

P.S.不要被我的视图中的“控制器”一词所迷惑 - 这是实体名称正在更新,而不是MVC控制器。

这里是控制器代码:

public partial class DeviceStationController : Controller 
{ 
    // GET: 
    public ActionResult MyDevicesSetup() 
    { 

     var tblUserDevice = db.TblUserDevices.Include(x => x.TblDevice).Include(x => x.TblDevicePrograms).Include(x => x.TblDeviceSensors).Include(x => x.TblDeviceStations).Include(x => x.TblUser).Where(x => x.TblUser.AspNetUser.UserName == User.Identity.Name); 
     var UserDevice_IDs = tblUserDevice.Select(p => p.Device_ID).Distinct(); 
     var tblDevice = db.TblDevices.Include(x => x.TblUserDevices).Where(x => UserDevice_IDs.Contains(x.Device_ID)); 

     return View(tblDevice.ToList()); 

    } 
    // POST: 
    [HttpPost] 
    [ValidateAntiForgeryToken] 
    public ActionResult MyDevicesSetup([Bind(Include = "Device_ID,DeviceCode,DeviceName,TimeZone,ExtBoards,Sequential,StationDelay,MasterStation,MastOnOffset,MastOffOffset,LocationZip,LocationCity,LocationCountry,DownloadFlag,LastDownload,LastUpload,RecordCreated,RecordEdited,RecordDeleted")] TblDevice tblDevice) 
    { 

     if (ModelState.IsValid) 
     { 
      tblDevice.RecordEdited = DateTime.Now; 
      db.Entry(tblDevice).State = EntityState.Modified; 
      db.SaveChanges(); 
      return RedirectToAction("MyDevicesSetup"); 
     } 

     return View(tblDevice); 
    } 
} 

这里是查看代码:

@model IEnumerable<AquaTame.Models.TblDevice> 

@{ 
ViewBag.Title = "Controller Setup"; 
} 

@foreach (var controller in Model) 
{ 
<div data-role="collapsible" data-collapsed-icon="carat-d" data-expanded-icon="carat-u" data-iconpos="right"> 
    <h4> 
     @controller.DeviceName 
    </h4> 
    @using (Html.BeginForm("MyDevicesSetup", "DeviceStation", routeValues: controller)) 
    { 
     @Html.AntiForgeryToken() 
     <div class="form-horizontal"> 

      @Html.ValidationSummary(true, "", new { @class = "text-danger" }) 
      @Html.HiddenFor(model => controller.Device_ID) 

      <div class="form-group"> 
       @Html.LabelFor(model => controller.DeviceCode, htmlAttributes: new { @class = "control-label col-md-2" }) 
       <div class="col-md-10"> 
        @Html.EditorFor(model => controller.DeviceCode, new { htmlAttributes = new { @class = "form-control" } }) 
        @Html.ValidationMessageFor(model => controller.DeviceCode, "", new { @class = "text-danger" }) 
       </div> 
      </div> 

@*More fields here..... removed for brevity...*@ 

      <input type="submit" value="Save" class="btn btn-default" /> 
     </div> 
    } 
</div> 
} 
@section Scripts { 
@Scripts.Render("~/bundles/jqueryval") 
} 

呈现给浏览器的HTML表单标签是在这里:

<form action="/DeviceStation/MyDevicesSetup?TblUserDevices=System.Collections.Generic.HashSet%601%5BAquaTame.Models.TblUserDevice%5D&amp;Device_ID=1&amp;DeviceCode=MX24B&amp;DeviceName=%231-w&amp;TimeZone=-8&amp;ExtBoards=0&amp;Sequential=True&amp;StationDelay=5&amp;MasterStation=False&amp;MastOnOffset=0&amp;MastOffOffset=0&amp;LocationZip=97124&amp;DownloadFlag=False&amp;RecordCreated=05%2F04%2F2014%2000%3A00%3A00&amp;RecordEdited=07%2F14%2F2014%2015%3A58%3A15&amp;RecordDeleted=True" method="post"> 

//lots of stuff here .... 

</form> 

的网址get的POST是如预期的那样;包含源自GET的原始元素:

http://localhost:59259/DeviceStation/MyDevicesSetup?TblUserDevices=System.Collections.Generic.HashSet%601%5BAquaTame.Models.TblUserDevice%5D&Device_ID=1&DeviceCode=MX24B&DeviceName=%231-w&TimeZone=-8&ExtBoards=0&Sequential=True&StationDelay=5&MasterStation=False&MastOnOffset=0&MastOffOffset=0&LocationZip=97124&DownloadFlag=False&RecordCreated=05%2F04%2F2014%2000%3A00%3A00&RecordEdited=07%2F14%2F2014%2016%3A10%3A36&RecordDeleted=True 

下面是更多从窗体中呈现的HTML。这些属性名称似乎保留得很好,但这超出了我理解“底层”情况的能力。我感谢所有有用的意见和建议:

<form action="/DeviceStation/MyDevicesSetup?TblUserDevices=System.Collections.Generic.HashSet%601%5BAquaTame.Models.TblUserDevice%5D&amp;Device_ID=1&amp;DeviceCode=MX24B&amp;DeviceName=%231-w&amp;TimeZone=-8&amp;ExtBoards=0&amp;Sequential=True&amp;StationDelay=5&amp;MasterStation=False&amp;MastOnOffset=0&amp;MastOffOffset=0&amp;LocationZip=97124&amp;DownloadFlag=False&amp;RecordCreated=05%2F04%2F2014%2000%3A00%3A00&amp;RecordEdited=07%2F14%2F2014%2016%3A11%3A21&amp;RecordDeleted=True" method="post"> 
<input name="__RequestVerificationToken" type="hidden" value="7-wHfkHpP50iZ4pekCWhIe0ahkvvE7KapaJjFkEhBfjZwtu8-bBfJvG1Pg-9ILn0FsXnrj8Jq1TJQKrq5DxQkaLxd7AVcxsQjqJegrwJL4VDIeR5H68QEPmqOQOu9AIIfdYzqON-iUDv4dFGg5IkXg2"> 
<div class="form-horizontal"> 
    <input data-val="true" data-val-number="The field Device_ID must be a number." data-val-required="The Device_ID field is required." id="controller_Device_ID" name="controller.Device_ID" type="hidden" value="1"> 
    <div class="form-group"> 
     <label class="control-label col-md-2" for="controller_DeviceCode">DeviceCode</label> 
     <div class="col-md-10"> 
      <div class="ui-input-text ui-body-inherit ui-corner-all ui-shadow-inset"> 
      <input class="form-control text-box single-line" id="controller_DeviceCode" name="controller.DeviceCode" type="text" value="MX24B"></div> 
      <span class="field-validation-valid text-danger" data-valmsg-for="controller.DeviceCode" data-valmsg-replace="true"></span> 
     </div> 
    </div> 
    <div class="form-group"> 
     <label class="control-label col-md-2" for="controller_DeviceName">DeviceName</label> 
     <div class="col-md-10"> 
      <div class="ui-input-text ui-body-inherit ui-corner-all ui-shadow-inset"> 
      <input class="form-control text-box single-line" data-val="true" data-val-length="The field DeviceName must be a string with a maximum length of 8." data-val-length-max="8" id="controller_DeviceName" name="controller.DeviceName" type="text" value="#1-w"></div> 
      <span class="field-validation-valid text-danger" data-valmsg-for="controller.DeviceName" data-valmsg-replace="true"></span> 
     </div> 
    </div> 
    @*More form fields in here, removed for brevity........*@ 
    <div class="ui-btn ui-input-btn ui-corner-all ui-shadow">Save<input type="submit" value="Save" class="btn btn-default"></div> 
</div> 
</form> 

我正在取得一些进展,每个人的帮助。我是MS MVC实体框架的新成员,并且自学成才,所以我恐怕缺乏一些关键知识。我已经从HTML BeginForm帮助器中删除了“controller”对象参数,并确保表单具有所有可用的字段。我已经将绑定前缀“控制器”添加到控制器上的绑定(非常令人困惑,我知道)。我现在收到返回给控制器的空数据,所以我仍然要做一些错误的事情。

这里是控制器代码:

 [HttpPost] 
    [ValidateAntiForgeryToken] 
    //public ActionResult MyDevicesSetup([Bind(Prefix = "controller")] TblDevice tblDevice) 
    public ActionResult MyDevicesSetup([Bind(Prefix = "controller", Include = "Device_ID,DeviceCode,DeviceName,TimeZone,ExtBoards,Sequential,StationDelay,MasterStation,MastOnOffset,MastOffOffset,LocationZip,LocationCity,LocationCountry,DownloadFlag,LastDownload,LastUpload,RecordCreated,RecordEdited,RecordDeleted")] TblDevice tblDevice) 
    { 

     if (ModelState.IsValid) 
     { 
      tblDevice.RecordEdited = DateTime.Now; 
      db.Entry(tblDevice).State = EntityState.Modified; 
      db.SaveChanges(); 
      //return RedirectToAction("MyDevicesSetup"); 
     } 
     return View(tblDevice); 
    } 
} 

这里是Razor视图代码:

@model IEnumerable<AquaTame.Models.TblDevice> 

@{ 
ViewBag.Title = "Controller Setup"; 
} 

@foreach (var controller in Model) 
{ 
<div data-role="collapsible" data-collapsed-icon="carat-d" data-expanded-icon="carat-u" data-iconpos="right"> 
    <h4> 
     @controller.DeviceName 
    </h4> 
    @*@using (Html.BeginForm("MyDevicesSetup", "DeviceStation", routeValues: controller))*@ 

     @using (Html.BeginForm("MyDevicesSetup", "DeviceStation")) 
    { 
     @Html.AntiForgeryToken() 
     <div class="form-horizontal"> 

      @Html.ValidationSummary(true, "", new { @class = "text-danger" }) 
      @Html.HiddenFor(model => controller.Device_ID) 
      @Html.HiddenFor(model => controller.DownloadFlag) 
      @Html.HiddenFor(model => controller.LastDownload) 
      @Html.HiddenFor(model => controller.LastUpload) 
      @Html.HiddenFor(model => controller.RecordCreated) 
      @Html.HiddenFor(model => controller.RecordEdited) 
      @Html.HiddenFor(model => controller.RecordDeleted) 

      <div class="form-group"> 
       @Html.LabelFor(model => controller.DeviceCode, htmlAttributes: new { @class = "control-label col-md-2" }) 
       <div class="col-md-10"> 
        @Html.EditorFor(model => controller.DeviceCode, new { htmlAttributes = new { @class = "form-control" } }) 
        @Html.ValidationMessageFor(model => controller.DeviceCode, "", new { @class = "text-danger" }) 
       </div> 
      </div> 

@*Remaining form fields follow - left out for brevity...*@ 

       <input type="submit" value="Save" class="btn btn-default" /> 
     </div> 
    } 

最后,在这里被发送到控制器从POST数据:

__RequestVerificationToken:NO1PIEHxKyzlNldFuOOt- 

EZhiU5VDe1Ax8CI9xzEzvViSgBqECKzmLrDRIdJeNOzMMJDaA-GTTBt5OeueTvnCKK6hK7MK_51EtANrVjwb5m4zVQY6tlHbnJcw3mdO9m5YhZi2eskyq4NhoHJHooL0g2 
controller.Device_ID:1 
controller.DownloadFlag:False 
controller.LastDownload: 
controller.LastUpload: 
controller.RecordCreated:5/4/2014 12:00:00 AM 
controller.RecordEdited:7/14/2014 4:11:21 PM 
controller.RecordDeleted:True 
controller.DeviceCode:MX24c 
controller.DeviceName:#1-w 
controller.TimeZone:-8 
controller.ExtBoards:0 
controller.Sequential:true 
controller.Sequential:false 
controller.StationDelay:5 
controller.MasterStation:false 
controller.MastOnOffset:0 
controller.MastOffOffset:0 
controller.LocationZip:97124 
controller.LocationCity: 
controller.LocationCountry: 
+1

当你拿起你的形式之一,并提交,什么是实际的HTML标记那种形式? POST请求中捕获的值是什么? (您可以使用浏览器调试工具(如Firebug或Chrome工具)检查这些工具。) – David

+1

用for循环替换每个 –

+0

在POST上,数据库中的数据是否正在更新? – Dbloch

回答

0

好的,所以我终于在@zespri和@Shoe的帮助下发现了解决方案(2部分)。第一部分是在视图中删除routeValues: controller,并将[Bind(Prefix = "controller")]添加到我的POST操作方法参数中。当我继续收到返回的空数据时,我发现了第二个关键问题。名为"controller"的变量必须导致某种冲突(在C#中是否为保留字?),因为只要我将其更改为“cntrlr”,一切正常。我仔细检查并重现了这个问题,所以我确信使用"controller"作为变量名称会导致问题。感谢大家的帮助!

工作控制器代码是在这里:

public partial class DeviceStationController : Controller 
    { 
     [HttpPost] 
     [ValidateAntiForgeryToken] 
     public ActionResult MyDevicesSetup([Bind(Prefix = "ctrlr", Include = "Device_ID,DeviceCode,DeviceName,TimeZone,ExtBoards,Sequential,StationDelay,MasterStation,MastOnOffset,MastOffOffset,LocationZip,LocationCity,LocationCountry,DownloadFlag,LastDownload,LastUpload,RecordCreated,RecordEdited,RecordDeleted")] TblDevice tblDevice) 
     { 

      if (ModelState.IsValid) 
      { 
       tblDevice.RecordEdited = DateTime.Now; 
       db.Entry(tblDevice).State = EntityState.Modified; 
       db.SaveChanges(); 
       return RedirectToAction("MyDevicesSetup"); 
      } 
      return View(tblDevice); 
     } 
    } 

而Razor视图代码是在这里:

@model IEnumerable<AquaTame.Models.TblDevice> 

@{ 
    ViewBag.Title = "Controller Setup"; 
} 

@foreach (var ctrlr in Model) 
{ 
    <div data-role="collapsible" data-collapsed-icon="carat-d" data-expanded-icon="carat-u" data-iconpos="right"> 
     <h4> 
      @ctrlr.DeviceName 
     </h4> 
     @using (Html.BeginForm("MyDevicesSetup", "DeviceStation")) 
     { 
      @Html.AntiForgeryToken() 
      <div class="form-horizontal"> 
       @Html.ValidationSummary(true, "", new { @class = "text-danger" }) 
       @Html.HiddenFor(model => ctrlr.Device_ID) 
       @Html.HiddenFor(model => ctrlr.DownloadFlag) 
       @Html.HiddenFor(model => ctrlr.LastDownload) 
       @Html.HiddenFor(model => ctrlr.LastUpload) 
       @Html.HiddenFor(model => ctrlr.RecordCreated) 
       @Html.HiddenFor(model => ctrlr.RecordEdited) 
       @Html.HiddenFor(model => ctrlr.RecordDeleted) 
       <div class="form-group"> 
        @Html.LabelFor(model => ctrlr.DeviceCode, htmlAttributes: new { @class = "control-label col-md-2" }) 
        <div class="col-md-10"> 
         @Html.EditorFor(model => ctrlr.DeviceCode, new { htmlAttributes = new { @class = "form-control" } }) 
         @Html.ValidationMessageFor(model => ctrlr.DeviceCode, "", new { @class = "text-danger" }) 
        </div> 
       </div> 

       <div class="form-group"> 
        @Html.LabelFor(model => ctrlr.DeviceName, htmlAttributes: new { @class = "control-label col-md-2" }) 
        <div class="col-md-10"> 
         @Html.EditorFor(model => ctrlr.DeviceName, new { htmlAttributes = new { @class = "form-control" } }) 
         @Html.ValidationMessageFor(model => ctrlr.DeviceName, "", new { @class = "text-danger" }) 
        </div> 
       </div> 

@* More form fields in here....*@ 

       </div> 
       <input type="submit" value="Save" class="btn btn-default" /> 
      </div> 
     } 
    </div> 
} 
@section Scripts { 
    @Scripts.Render("~/bundles/jqueryval") 
} 
1

您需要在您的视图中删除routeValues: controller并将[Bind(Prefix = "controller")]添加到您的操作中离子方法参数。

你的routeValues: controller掩盖了你的问题,而不是解决它。它将这个长查询字符串添加到您的表单操作,然后添加到发布的URL。来自发布表单的数据来自POST请求,而不是来自url,尽管默认的模型联编程序可以处理两者。因此,您的情况发生了什么:您需要将这些未更改的数据纳入其中,但无法绑定回发数据,因为它们与视图中的“controller”变量相关联,并且action方法参数具有不同的名称: tblDevice。您需要将前缀参数添加到“绑定”属性以解决此问题。

此外,在这种情况下,我强烈建议查看回发数据,因为它们会立即提供关于哪些内容可能出错(在本例中为前缀)的线索。大卫在第一条评论中向你提出这个建议,但你可能忽略了这个建议。

+0

非常感谢你的帮助。我在MS MVC实体框架中是全新的自学,所以请原谅我缺乏某些知识。我现在了解绑定前缀和使用内置Chrome调试器查看POST数据。确实非常有用。我仍然坚持将空值返回给控制器。我尝试了多种使用前缀的方法,并确保所有字段都可以从表单中获得。恐怕我仍然错过了一些明显的东西。 – ChrisS

+0

所以当你进入MyDevicesSetup中的调试器时,什么是null,tblDevice或它的属性? –

+0

当您进入控制器例程时,tblDevice本身为空。没有任何属性。 – ChrisS

相关问题