0

In my mvc application I have a lot of related data, I need to write a method to allow the edit/update of that related data, at the moment my data is handled using a ViewModel. I have attempted to write a method to do this but I can't get it to work correctly and I'm not sure my approach is quite right and so I wanted to get some guidance.

Here is my code:

Controller Code

[HttpPost]
[ValidateAntiForgeryToken]
    public ActionResult Edit(FullVesselViewModel model)
    {
        var vessel = new tbl_vessels
        {
            vessel_idx = model.vessel_idx,
            vessel_name = model.vessel_name
        };
        var vessel_spec = new tbl_vessel_spec
        {
            spec_idx = model.spec_idx,
            bhp = model.bhp
        }
        using (var context = new dataEntities())
        {
            context.Entry(vessel).State = EntityState.Modified;
            context.Entry(vessel_spec).State = EntityState.Modified;                               
            context.SaveChanges();
            return RedirectToAction("Index");
        }
    }

My initial though was to declare my viewmodel and then break down the two related entities and store them in variables, comitting those variables as modified and then saving my changes. My above approach returns concurrency errors. I have stored the indexes of the entities in a couple of hidden for fields to see if that would help but I've had no luck.

View

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    @Html.HiddenFor(model => model.vessel_idx)
    @Html.HiddenFor(model => model.spec_idx)


    ...input fields etc ...
}

Is my thinking correct for this sort of scenario or have I over engineered something that can be done simpler?

The error that I get is as follows and is triggered at SaveChanges():

Entity Framework: “Store update, insert, or delete statement affected an unexpected number of rows (0).”
Yanayaya
  • 2,044
  • 5
  • 30
  • 67
  • Please note that the model-view-controller tag is for questions about the pattern. There is a specific tag for the ASP.NET-MVC implementation. –  Jul 19 '16 at 09:44
  • What kind of concurrency errors happened? Usually for similar cases I find matched data by lambda or LINQ query first, if the data exists execute `this.UpdateModel` and `context.SaveChanges()` to save changes into DB. – Tetsuya Yamamoto Jul 19 '16 at 09:53
  • I've added the error above @TetsuyaYamamoto – Yanayaya Jul 19 '16 at 10:39

1 Answers1

0

After analyzing your code & found context.SaveChanges() as source of EF exception, you may choose one of these solutions that suitable for your issue.

Change EntityState to Added before saving changes:

using (var context = new dataEntities())
{
    context.Entry(vessel).State = EntityState.Added;
    context.Entry(vessel_spec).State = EntityState.Added;                               
    context.SaveChanges();
    return RedirectToAction("Index");
}

or use TryUpdateModel inside your controller action after finding data matches, in case you need data update without changing primary key:

var foundvessel = context.tbl_vessels.Where(x => x.vessel_idx == model.vessel_idx).FirstOrDefault();

var foundvspec = context.tbl_vessel_spec.Where(x => x.spec_idx == model.spec_idx).FirstOrDefault();

if (foundvessel != null && foundvspec != null)
{
    var vessel = new tbl_vessels
    {
        vessel_idx = model.vessel_idx,
        vessel_name = model.vessel_name
    };
    var vessel_spec = new tbl_vessel_spec
    {
        spec_idx = model.spec_idx,
        bhp = model.bhp
    }

    using (var context = new dataEntities())
    {
        this.TryUpdateModel(vessel);
        this.TryUpdateModel(vessel_spec);                               
        context.SaveChanges();
        return RedirectToAction("Index");
    }
}

EF's generated error indicates an optimistic concurrency exception where you trying to update primary key value of some table(s), i.e. if vessel_idx & spec_idx are primary key from each target table EF treats modifying them as adding new row(s), rather than updates against existing data.

Thus, you need to perform:

  • EntityState.Added if new primary key has added

  • EntityState.Modified if existing primary key left unchanged

Any improvements or suggestions welcome.

Additional reference: Entity Framework: "Store update, insert, or delete statement affected an unexpected number of rows (0)."

Community
  • 1
  • 1
Tetsuya Yamamoto
  • 24,297
  • 8
  • 39
  • 61