My Model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace SNW.Models.CustomerOrderInfo
{
public class MemberOrder : CustomerOrder
{
public new int customerOrderID { get; set; }
[..]
public int customerOrderLineID { get; set; }
public int productID { get; set; }
[..]
public double customerOrderQtyMin { get; set; }
public double customerOrderQtyMax { get; set; }
[..]
}
}
My Controller:
[..]
using SNW.Models;
using SNW.Models.CustomerOrderInfo;
namespace SNW.Controllers
{
public class CustomerOrderController : Controller
{
private DBModelContainer db = new DBModelContainer();
[HttpPost, ActionName("SaveChanges")]
public ActionResult SaveChanges([Bind(Include = "customerOrderQtyMax")] SNW.Models.CustomerOrderInfo.MemberOrder line)
{
if(ModelState.IsValid)
{
db.Entry(line).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("CustomerOrder");
}
return View(line);
}
}
}
My View (CustomerOrder.cshtml):
@model IEnumerable<SNW.Models.CustomerOrderInfo.MemberOrder>
[..]
@foreach (var MemberOrder in Model)
{
<tr>
<td>@MemberOrder.productID</td>
<td>@MemberOrder.productName</td>
[..]
<td>@Html.EditorFor(model => MemberOrder.customerOrderQtyMin)</td>
<td>
@using (Html.BeginForm("SaveChanges", "CustomerOrder", new { id = MemberOrder.customerOrderLineID }))
{
@Html.ValidationSummary(true)
@Html.HiddenFor(model => MemberOrder.customerOrderLineID)
@Html.EditorFor(model => MemberOrder.customerOrderQtyMax)
@Html.ValidationMessageFor(model => MemberOrder.customerOrderQtyMax)
<input type="submit" value="+" class="btn btn-default" />
}
</td>
[..]
</tr>
Rendered View:
The Problem:
Whenever I change Max value of Order Line and click "+" to update it in database, it doesn't work.
The line
values in SaveChanges()
method comes as either 0 or null, including customerOrderQtyMax
value which is 0.0, but DB update doesn't happen either - former values are being shown again.
So my question is, how do I pass only customerOrderQtyMax
input value to DB from this IEnumerable View? I want' to be able to amend order (or shopping cart if you wish) values right in CustomerOrder.cshtml page.
What have I tried so far:
Updating Related Data with the Entity Framework in an ASP.NET MVC Application
Comparing
SaveChanges()
method toEdit()
method generated from DB Model by EF6 forCustomerOrderLines
entity. The later is not using IEnumerables<> and it has it's own View (Edit.cshtml).Added an extra
HiddenFor()
field in my View as my Order Lines' primary keys are composed ofcustomerOrderLineID
andcustomerOrderID
attributes.
@using (Html.BeginForm("SaveChanges", "CustomerOrder", new { id = MemberOrder.customerOrderLineID }))
{
@Html.ValidationSummary(true)
@Html.HiddenFor(model => MemberOrder.customerOrderLineID)
@Html.HiddenFor(model => MemberOrder.customerOrderID)
@Html.EditorFor(model => MemberOrder.customerOrderQtyMax)
@Html.ValidationMessageFor(model => MemberOrder.customerOrderQtyMax)
<input type="submit" value="+" class="btn btn-default" />
}
Thank you for your help, guys!
EDIT:
I've changed the code in SaveChanges()
method quite a few times, but here is what errors I received:
- Reference to
SNW.Models.CustomerOrderInfo.MemberOrder
inpublic ActionResult SaveChanges([Bind(Include = "customerOrderQtyMax")] SNW.Models.CustomerOrderInfo.MemberOrder line)
awards me with following error: {"The entity type MemberOrder is not part of the model for the current context."} probably because it's my custom made Model which inherits fromCustomerOrder
Model, becauseCustomerOrder
can be overwritten by EF Model generator- I need to use extra custom made properties for calculations
- Changed
SNW.Models.CustomerOrderInfo.MemberOrder
to originalCustomerOrderLine
and received following error: {"Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries."}.CustomerOrderLine
is generated by EF Model generator and I want its properties to merge withCustomerOrder
to be able to edit Order's information in one window rather then going to Edit View for every single row (order line). That's why I made customSNW.Models.CustomerOrderInfo.MemberOrder
Model.- Now
SaveChanges()
ispublic ActionResult SaveChanges([Bind(Include = "customerOrderQtyMax")] CustomerOrderLine line)
- @Jasen. HTTP POST Header Thank you.
Request URL:http://localhost:64778/CustomerOrder/SaveChanges/8 Request Method:POST Status Code:500 Internal Server Error Request Headersview parsed POST /CustomerOrder/SaveChanges/8 HTTP/1.1 Host: localhost:64778 Connection: keep-alive Content-Length: 68 Cache-Control: max-age=0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Origin: http://localhost:64778 User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36 Content-Type: application/x-www-form-urlencoded Referer: http://localhost:64778/CustomerOrder/CustomerOrder Accept-Encoding: gzip,deflate,sdch Accept-Language: en-GB,en;q=0.8,lt;q=0.6 Cookie: .ASPXFORMSAUTH=F44D36B23D1EA17ABB24DEEC4AFA7B09FD2D7B3EEB8D9C57D95561E9A9B334F4BA90F46AEAC2E2DE23958998B3F888342E507B92484C45D990CD0FD08D38F8D8D994CC8F5C231A0144DE4A7B89A286A1AFFEE765C86C856E71403FF94FDF873E Form Dataview parsed MemberOrder.customerOrderLineID=8&MemberOrder.customerOrderQtyMax=78 Response Headersview parsed HTTP/1.1 500 Internal Server Error Cache-Control: private Content-Type: text/html; charset=utf-8 Server: Microsoft-IIS/8.0 X-AspNet-Version: 4.0.30319 X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcRG9uYXRhc1xTb3VyY2VcUmVwb3NcU291bmRzTmljZVdob2xlZm9vZHNcU05XXFNOV1xDdXN0b21lck9yZGVyXFNhdmVDaGFuZ2VzXDg=?= X-Powered-By: ASP.NET Date: Wed, 09 Apr 2014 21:03:23 GMT Content-Length: 17180
HTML Form:
<form action="/CustomerOrder/SaveChanges/8" method="post">
<input data-val="true" data-val-number="The field customerOrderLineID must be a number." data-val-required="The customerOrderLineID field is required." id="MemberOrder_customerOrderLineID" name="MemberOrder.customerOrderLineID" type="hidden" value="8">
<input class="text-box single-line" data-val="true" data-val-number="The field customerOrderQtyMax must be a number." data-val-required="The customerOrderQtyMax field is required." id="MemberOrder_customerOrderQtyMax" name="MemberOrder.customerOrderQtyMax" type="text" value="3">
<span class="field-validation-valid" data-valmsg-for="MemberOrder.customerOrderQtyMax" data-valmsg-replace="true"></span>
<input type="submit" value="+" class="btn btn-default">
</form>
- Tried a solution from this StackOverflow answer and changed the code to
[HttpPost, ActionName("SaveChanges")] public ActionResult SaveChanges([Bind(Include = "customerOrderQtyMax")] CustomerOrderLine line) // whitelist fields { CustomerOrderLine lineTemp = new CustomerOrderLine() { customerOrderQtyMax = line.customerOrderQtyMax }; if(ModelState.IsValid) { db.Entry(lineTemp).State = EntityState.Added; db.SaveChanges(); return RedirectToAction("CustomerOrder"); } return View(lineTemp); }
And now got this error: {"Cannot add or update a child row: a foreign key constraint fails (\"c1snw\".\"CustomerOrderLines\", CONSTRAINT \"FK_ProductCustomerOrderLine\" FOREIGN KEY (\"productID\") REFERENCES \"Products\" (\"productID\") ON DELETE NO ACTION ON UPDATE NO ACTION)"}, which probably means... well, I'm not sure if correct line is selected from DB using this code and whether it is trying to Update or Add a new line. Will check that.
SOLUTION:
@Jasen's suggestion of using Prefix="MemberOrder"
in Bind helped to get code working!
However, I got rid of Include=
statement in Bind, because it only worked when all line's attributes, that are not initially empty (null or 0) are included, and since I need all of them, I removed Include=
in Controller and added more HiddenFor
fields in the View. If I haven't had done this, Controller would attempt to change initial values to null) or 0.
Final code:
My Controller:
[HttpPost, ActionName("SaveChanges")]
public ActionResult SaveChanges([Bind(Prefix="MemberOrder")] CustomerOrderLine line) // whitelist fields
{
if(ModelState.IsValid)
{
db.Entry(line).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("CustomerOrder");
}
return View(line);
}
My View:
@using (Html.BeginForm("SaveChanges", "CustomerOrder", new { id = MemberOrder.customerOrderLineID }))
{
@Html.ValidationSummary(true)
@Html.HiddenFor(model => MemberOrder.customerOrderLineID)
@Html.HiddenFor(model => MemberOrder.customerOrderID)
@Html.HiddenFor(model => MemberOrder.productID)
@Html.HiddenFor(model => MemberOrder.customerOrderQtyMin)
@Html.EditorFor(model => MemberOrder.customerOrderQtyMax)
@Html.HiddenFor(model => MemberOrder.customerOrderQtyActual)
@Html.ValidationMessageFor(model => MemberOrder.customerOrderQtyMax)
<input type="submit" value="+" class="btn btn-default" />
}