Ellis
Ellis

Reputation: 105

ASP.NET MVC entity validation error on trying to save database changes

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

Answers (3)

Shahbaz Raees2
Shahbaz Raees2

Reputation: 221

updating the Entity data Model will work

Upvotes: 1

user3559349
user3559349

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

Amr Alaa
Amr Alaa

Reputation: 1176

try to use

db.Set<ProductNote>().AddOrUpdate(productNote);
db.SaveChanges();

without

db.Entry(productNote).State = EntityState.Modified;

Upvotes: 0

Related Questions