Reputation: 105
I have been trying to complete a simple application I was given for practice at my summer internship. I have almost no background in ASP.NET so I was given extra work. I am trying to get a database entry to update from an http post function in c#, however when the function runs it throws a validation error. I have been trying to find reasons for the error, however I cannot seem to figure out why it is not working. Any help is appreciated.
Here is the error:
Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
Source Error:
Line 130: db.Entry(productNote).State = EntityState.Modified;
Line 131: db.SaveChanges();
Line 132: return RedirectToAction("Index");
Source File: C:\Users\Morph\Documents\Visual Studio 2015\Projects\NotesWebApp\NotesWebApp\Controllers\ProductsController.cs Line: 131
Here is the http post function in my Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index([Bind(Include = "ID,ProductID,NoteText,CreateDate,Archived")] ProductNote productNote)
{
Response.Write("<script type=\"text/javascript\">alert('Works');</script>");
if (ModelState.IsValid)
{
db.Entry(productNote).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return RedirectToAction("Index");
}
Here is the form I am submitting to the function:
@using (Html.BeginForm()) {
@Html.AntiForgeryToken()
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(noteItem => note.ID)
@Html.HiddenFor(noteItem => note.ProductID)
@Html.HiddenFor(noteItem => note.NoteText)
@Html.HiddenFor(noteItem => note.CreateDate)
<div class="checkbox">
@Html.EditorFor(noteItem => note.Archived)
@Html.ValidationMessageFor(noteItem => note.Archived, "", new { @class = "text-danger" })
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
}
Upvotes: 1
Views: 7560
Reputation:
The reason for the error is that you generating forms in a foreach
loop and as a result the controls have name
attributes that have no relationship to your model (refer HTML Table to ADO.NET DataTable for more information). As a result, your POST method just initializes a new ProductNote
with default properties (presumably ID
is int
so its value will be 0
).
Even if you did generate the view correctly, you are degrading your app by generating a whole lot a unnecessary html and posting it back, but more importantly, a malicious user could easily change all the data in your ProductNote
table without you knowing.
From your comments, you just wanting to submit a form to mark a single ProductNote
as archived. Start by creating a method that represents what you want to do
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Archive (int ID)
{
// Get the original
ProductNote model = db.ProductNote.FirstOrDefault(x => x.ID == ID);
// If the user has the permission to archive and the model is not null
model.Archived = true;
db.SaveChanges();
return RedirectToAction("Index");
}
And change the view to
@foreach(var note in Model.ProductNotes)
{
@Html.DisplayFor(m => note.NoteText)
....
@using (Html.BeginForm("Archive", "Products", new { id = note.ID }))
{
@Html.AntiForgeryToken()
<input type="submit" value="Archive" />
}
}
You will also want to consider handling the forms .submit()
event to display a confirm message (or alternatively just use a link to a GET method that displays a confirm page and make the POST from there). In addition, you should consider using ajax to post the ID
value, so that you can stay on the same page and continue to archive further ProductNote
items.
Upvotes: 3
Reputation: 1176
try to use
db.Set<ProductNote>().AddOrUpdate(productNote);
db.SaveChanges();
without
db.Entry(productNote).State = EntityState.Modified;
Upvotes: 0