23

I keep getting the following error when I try to save changes made to a context:

Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.

I have the following classes:

Person

public class Person : IPerson
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string Name
    {
        get
        {
            return FirstName + " " + LastName;
        }
        set{}
    }

    public string Email { get; set; }
    public DateTime? LastModified { get; set; }
    public virtual ICollection<Result> Results { get; set; }
}

UserProfile

public class UserProfile : Person
{
    public UserProfile()
    {
        Faculty = new Faculty();
        Projects = new Collection<Project>();
        Results = new Collection<Result>();
    }
    public string UserName { get; set; }
    public string CNP { get; set; }
    public virtual Faculty Faculty { get; set; }
    public virtual ICollection<Project> Projects { get; set; }
}

Result

public abstract class Result:INamedEntity
{
    protected Result()
    {
        ResultType = new ResultType();
    }
    public int Id { get; set; }
    public string Name{get;set;}
    public virtual ResultType ResultType { get; set; }
    public virtual ICollection<Person> People { get; set; }
    public DateTime? LastModified { get; set; }
}

After I add a value to the context using:

_ctx.Users.Single(u => u.Id == userId).Results.Add(result);

I get the error when i call _ctx.SaveChanges()

Updated my function to:

public bool Save()
{

    try
    {
        _ctx.SaveChanges();
    }
    catch (OptimisticConcurrencyException)
    {
        ((IObjectContextAdapter)_ctx).ObjectContext.Refresh(RefreshMode.ClientWins,_ctx.Users);
        ((IObjectContextAdapter)_ctx).ObjectContext.Refresh(RefreshMode.ClientWins,_ctx.Results);
        _ctx.SaveChanges();
    }
    return true;
}

But the error isn't caught. Thank you

Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Bobby Tables
  • 2,953
  • 7
  • 29
  • 53

16 Answers16

41

Add this to your edit.cshtml

@Html.HiddenFor(model => model.Id)

I had this issue and found that the ID was coming across as 0 since it was not on the page.

I also have this on my ViewModel (I am using the view model approach)

[HiddenInput(DisplayValue = false)]
[Key]
public int Id { get; set; }
VoltaicShock
  • 842
  • 2
  • 7
  • 19
  • 2
    Totally saved me hours of headaches! Great catch. – PortageMonkey Jun 04 '14 at 02:59
  • Thanks @Terry. Best answer. – Kanapolis Oct 27 '15 at 16:46
  • 1
    I was wondering why that field wasn't in the generated razor and discovered that in the model there was this data annotation [ScaffoldColumn(false)] – AnotherOther Jan 06 '16 at 17:10
  • 1
    This was essentially my problem, but your solution didn't work for me. Turns out that was because the form was inside a `@foreach` loop in my view, and controls in such loops do not bind correctly for posting back in Razor. My solution was, instead of using a `@Html.HiddenFor` control, to manually create the HTML input and ensure its name matched the model's field I was binding to, e.g. `` – Philip Stratford Aug 17 '17 at 10:54
16

Figured it out. The problem was that there's two of us working on this project, and my colleague created his own instance of DBContext he was updating one and i the other. So for who ever has this problem in the future make sure you don't have two different instances of your DBContext at the same time

Bobby Tables
  • 2,953
  • 7
  • 29
  • 53
3

For me the problem was that i didn't had set the action bindings correctly:

public ActionResult Edit([Bind(Include = "VehicleID,Name,CreateDate,PowerPS,DrivenKM")] Car car)
    { ... }

The VehicleID was mapped with the wrong identifier, therefore Entity Framework always got 0 as primary key.

Thomas
  • 573
  • 1
  • 5
  • 16
2

Your exception means that between time when you fetched data from database and modified it ,Your data had been changed.

By default, the Entity Framework implements an optimistic concurrency model. This means that locks are not held on data in the data source between when the data is queried and the data is updated. MSDN

how to manage concurrency in an object context.MSDN

Or follow this answer which refreshes context. StackOverflow

Community
  • 1
  • 1
Suraj Singh
  • 4,041
  • 1
  • 21
  • 36
1

If ever you came across to this problem and non of the above solutions helped you, maybe you can try this. I also had this weird issue, and the way I was able to have it fixed is I have set the a field to primary key and have it auto increment or set to Identity. Say you have the Person table and you have a personID maybe, set it to primary key and make sure it is auto incremented.

Clyde
  • 732
  • 8
  • 19
1

add the following overload to my DbContext class:

using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;

public class MyDbContext: DbContext {
...
        public int SaveChanges(bool refreshOnConcurrencyException, RefreshMode refreshMode = RefreshMode.ClientWins) {
            try {
                return SaveChanges();
            }
            catch (DbUpdateConcurrencyException ex) {
                foreach (DbEntityEntry entry in ex.Entries) {
                    if (refreshMode == RefreshMode.ClientWins)
                        entry.OriginalValues.SetValues(entry.GetDatabaseValues());
                    else
                        entry.Reload();
                }
                return SaveChanges();
            }
        }
}

Then called SaveChanges(true) wherever applicable.

Tony Trembath-Drake
  • 1,638
  • 3
  • 13
  • 14
0

There is a conflict, as you are using optimistic locking. Resolve concurrency issues using the ObjectStateManager entries, and Save changes again. Some sample code is there in MSDN site.

vijayst
  • 20,359
  • 18
  • 69
  • 113
0

I came across this when googleing. I had the same error message but the reason turned out to be that i did not set some mandatory non null values.

Maybe this finding helps someone.

r0m4n
  • 13
  • 3
0

I ran into this error message as well. What caused my error was primary / foreign key conflicts. I had pushed some new data into my DB and my foreign key values were off (mistake in my upload script).

Use SQL Profiler to help track down the offending insert script, this will likely help you discover what the issue with the update.

Hope this helps anyone else with similar issues.

0

Thanks Terry, Let's add this: Do NOT add [Required] attribute to your Key/ID when scaffolding. This stops your context from pulling the key/id from the url. Also: This happened to me in a scaffold controller after a migration which included new boolean fields on the model. These fields were not set.

0

Make sure you are passing the ID for both tables to the model from the view. In your case it's the key for the table Person and UserProfile. If you dont need to show the ID on the page you can add @Html.HiddenFor(model => model.PersonId) and @Html.HiddenFor(model => model.UserProfileId)

IndieTech Solutions
  • 2,527
  • 1
  • 21
  • 36
0

I encountered this error when creating a project, even just trying to do a simple insert.

We were generating the EF model from a pre-existing database, and the framework automatically set Entity Key = True on multiple fields.

Setting all but the ID to False solved the problem.

Wildcat Matt
  • 388
  • 4
  • 13
0

I don't know what exactly was wrong but i just did these steps and it got resolved. (I hope you will be able to resolve this as i was able to do it)
Steps are as follows:
(1) Add the new controller using scaffolding on the basis of your edmx table and the DB context of EF file.
(2) Now where the save changes creates the problem is edit method.
(3) Now copy the edit method/ whole controller made out of scaffolding and paste it in your original controller.
(4) now just build the program and Voila you are good to go.

Update
I found out that for data to be edited from view all the fields must be sent for written again to controller. If at the time of edition any of the fields from entity table is missing it will not allow to be editted. Especially if PK is in Label and sent to controller for edit then it will generate this error.

0

In my case, I had a composite key and was trying to update part of it (3 columns constitutes a composite key, out of which i was updating 3rd column only) but EF didn't allow changing key values for the same object, I achieved updating the record through:

Context.Database.ExecuteSqlCommand(udpateCommand);
Sadiq
  • 786
  • 1
  • 10
  • 35
0

Well, I also faced this type of concurrency error while working with Entity Framework 6.13 using Code First. And I also struggled for hours before solving it myself. So it can help someone out there. A table was created with composite primary keys and today I changed the structure of the table and made only one primary key(with AutoIncrement) instead of composite keys and update the table through migrations with fluent-api configurations. Table got updated but the primary key was not updated with AutoIncrement and whenever I tried to add a record, it showed the concurrency error. So, as I set the autoincrement of the field and the error was gone. Hope, it helps.

VID
  • 13
  • 1
  • 6
-1

I fixed some code that was giving the same error message when trying to update a record. I had the following code initially:

[HttpPost]
    public ActionResult Edit(Project project)
    {
        if (ModelState.IsValid)
        {

            entity.Entry(project).State = EntityState.Modified;
            entity.SaveChanges();

            return RedirectToAction("Index", "Home");
        }
        return View(project);
    }

Instead of the following code

   [HttpPost]
    public ActionResult Edit(Project project)
    {
        if (ModelState.IsValid)
        {

            entity.Entry(project).State = EntityState.Added;
            entity.SaveChanges();

            return RedirectToAction("Index", "Home");
        }
        return View(project);
    }
Nathan Tuggy
  • 2,237
  • 27
  • 30
  • 38
Glozz
  • 17
  • 4