1

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>
}
Ellis
  • 105
  • 2
  • 10
  • 1
    What does _See 'EntityValidationErrors' property for more details_ tell you. And refer [How to create a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve). 90% of this code is irrelevant to your issue –  Jun 30 '16 at 03:24
  • Going to the msdn page for Entity Validation Errors tells me very little about why I am having the problem. I had already visited and tried looking at the information – Ellis Jun 30 '16 at 03:41
  • You need to break on the exception and look at the EntityValidationErrors property – mitchellJ Jun 30 '16 at 03:44
  • Your _EntityValidationErrors_ - its a property of the Exception! (debug your code) –  Jun 30 '16 at 03:44
  • 2
    Hi @Ellis, you can refer to [this](http://stackoverflow.com/questions/5345890/getting-exact-error-type-in-from-dbvalidationexception/6593432#6593432) to help you get the exact error messages. – Shawn Yan Jun 30 '16 at 03:51
  • And there is something weird about your expressions -`@Html.HiddenFor(noteItem => note.ID)` etc which does not make sense. I suspect you have a loop and this is generate html with `name="note.ID"` which would never bind to your model and all your properties of `ProductNote` will be there default values. –  Jun 30 '16 at 04:26
  • Okay, I am using a loop to create the forms, are their any alternatives that would allow it to work. I checked further and the values are coming back as null, so I assume you are correct. – Ellis Jun 30 '16 at 04:31
  • what is "note"? syntax of hidden field should be like this @Html.HiddenFor(noteItem => noteItem.ID) – Pawan Lakhara Jun 30 '16 at 04:33
  • Why in the world would you use a loop to create multiple forms (you can only submit one form at a time). If you wanting to edit only one item, then generate links that take you to a separate edit view (or use javascript in conjunction with a modal form to popup a form that is populated with the details of that item) –  Jun 30 '16 at 04:33
  • please show your ProductNote entity class. – Pawan Lakhara Jun 30 '16 at 04:36
  • I had that setup before, however one of the requirements for the project is that the user can edit the archive variable from the same page that all the notes can be viewed – Ellis Jun 30 '16 at 04:36
  • 1
    Then your approach is wrong. You can create a form for each item with a route value only for the ID and post to `public ActionResult Archive(int ID)` (and you could do that using ajax so that the user can continue to archive notes while staying on the same page) –  Jun 30 '16 at 04:39
  • How could I create a form for each item without using a loop and running into the same problem. The amount of notes is fluid, more can be added at anytime. I cannot see a way around this without using a loop of some kind. – Ellis Jun 30 '16 at 04:48
  • please map your database column and your entity class (ProductNote) data type. both should be same. – Pawan Lakhara Jun 30 '16 at 04:50
  • Read my last comment (_create a form for **each** item_ is a loop) –  Jun 30 '16 at 04:51

3 Answers3

3

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.

Community
  • 1
  • 1
1

updating the Entity data Model will work

Shahbaz Raees2
  • 201
  • 2
  • 5
0

try to use

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

without

db.Entry(productNote).State = EntityState.Modified;
Amr Alaa
  • 1,156
  • 11
  • 16
  • 1
    The OP encountered DbEntityValidationException , which mostly revolves on one or more fields not inserted properly. Checking whether the record exist in database does not solve OP problem. – Shawn Yan Jun 30 '16 at 04:21
  • he checking if the model is valid or not and it gives true so I think the validation problem have something to do with the id ... and addOrUpdate method take care of that .. that's why I gave this answer – Amr Alaa Jun 30 '16 at 05:10