I’m trying to make a website using asp.net mvc 4 & EF6 where I want to update multiple rows all at once. But for some reason, it’s not working & I get an error like this,
System.NullReferenceException: Object reference not set to an instance of an object
Here are my codes,
Controller
[HttpPost]
public ActionResult MakeDue(List<BillCheck> BillLists)
{
if (Session["username"] != null)
{
if (ModelState.IsValid)
{
foreach (var BillId in BillLists)
{
var getDue = db.BillChecks.Where(p => p.id == BillId.id).FirstOrDefault();
getDue.due = BillId.due;
}
db.SaveChanges();
return RedirectToAction("Success");
}
else
{
return RedirectToAction("Failed");
}
}
else
{
return RedirectToAction("Login");
}
}
View
@using (Html.BeginForm("MakeDue", "Home"))
{
@Html.ValidationSummary(true)
@foreach(var item in Model.DueList)
{
@Html.HiddenFor(modelItem => item.id)
<tr>
<td>@Html.DisplayFor(modelItem => item.flat)</td>
<td>@Html.DisplayFor(modelItem => item.name)</td>
<td>@Html.TextBoxFor(modelItem => item.due)</td>
</tr>
}
<input type="submit" class="btn btn-success" value="Update" />
}
Is there something wrong in my code? How can I update all the inputs for due given at once?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
Your first problem is that your use of a foreach loop is generating duplicate name attributes, which will not bind to a collection, and as a result the BillLists parameter will always be an empty collection (its also generating duplicate id attributes which is invalid html). You need to use a for loop or a custom EditorTemplate for typeof BillCheck. Using a for loop, your view need to be
using (Html.BeginForm("MakeDue", "Home"))
{
@Html.ValidationSummary(true)
@for(int i = 0; i < Model.DueList.Count; i++)
{
<tr>
<td>
@Html.HiddenFor(m => m.DueList[i].id)
@Html.DisplayFor(m => m.DueList[i].flat)</td>
<td>@Html.DisplayFor(m => m.DueList[i].name)</td>
<td>@Html.TextBoxFor(m => m.DueList[i].due)</td>
</tr>
}
<input type="submit" class="btn btn-success" value="Update" />
}
Note also that the @Html.HiddenFor() helper need to be inside a <td> element in order to be valid html.
The next problem is that the model in the view is not typeof List<BillCheck>, but it does contain a property named DueList, which is typeof List<BillCheck> so your POST method needs to be
public ActionResult MakeDue(YourModel model)
where YourModel is the class name you used to generate the view (i.e. in the @model ??? statement). Then you loop in the controller method need to be
foreach (var BillId in model.DueList)
{
var getDue = db.BillChecks.Where(p => p.id == BillId.id).FirstOrDefault();
if (getDue != null) // add this
{
getDue.due = BillId.due;
}
}
db.SaveChanges();
Note also the addition of the if (getDue != null) check.
Side note: Your are checking if (ModelState.IsValid). It is recommended you return the view if ModelState is not valid so that the user can correct any errors.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0