105

I'm using generic repository pattern in asp.net core 2.0 which can not dispose repository object, when I am going to update the entry its updated for one time successfully but when I am trying to update for more then once it throws the following exception:

The instance of entity type 'Company' cannot be tracked because another instance with the same key value for {'ID'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.

public ActionResult Edit(Int64 id, Company collection)
{
    try
    {
        // TODO: Add update logic here
        interfaceobj.updateModel(collection);
        interfaceobj.Save();
        return RedirectToAction(nameof(Index));
    }
    catch(Exception ex)
    {
        throw ex;
    }
}
4
  • 1
    Read How to Ask and create a minimal reproducible example. You shouldn't reuse DbContext between requests. Commented Jan 11, 2018 at 8:47
  • It would be great if you had provided some code instead of saying I've implemented Repository Pattern. The problem seems to exist in how you've implemented that! This question is not helping others with the same problem. Commented Jul 28, 2020 at 8:24
  • There's nothing in the code that shows what EF does, it's all hidden behind custom code. This can't possibly be answered. What is interfaceobj? What is the status of the code? Why the TODO? Etc. Commented May 4, 2021 at 11:22
  • JIC, I was having this issue, and it turned out I was inserting multiple items using the same Id. Commented Sep 14, 2024 at 11:42

10 Answers 10

94

Your DB Context is being shared by multiple requests, meaning that the entity you're editing has been tracked already.

This is likely because your repository service is a Singleton rather than Scoped, and so your DB Context is being reused with the entity being tracked when it's pulled out, and then put back in to the same instance of the DB Context.

Instead of a Singleton repository, use a Scoped Repository, which means that a new instance will be created for each request. Likewise, you will also have a per-request DB Context.

When you register your service it will be using services.AddSingleton<..>

Change this to services.AddScoped<..>, when you inject it into your controller you will then get a new instance per request and your updates should work fine.

Sign up to request clarification or add additional context in comments.

12 Comments

my bad i was registring for singlton service services.AddSingleton<IRepository<Company>, GenericRepository<Company>>(); and now i changed it into service.AdScoped and now it works perfectly for me :)
@Andre are you initialising another DB Context somewhere?
Actually I was using Scoped already, I have solved the problem and seems to be a EF bug...
@JonathanPeel, on my case it was an EF bug as far I know... so to solve, first of all I made some changes in order to see the query like here stackoverflow.com/q/1412863/4482337, after that I saw that EF was doing something very weird, somehow it was trying to put data that was already there and I notice that it was always the same attribute with problem, well at the end I discovered that somehow EF was getting lost because I had the attribute string "name" on many classes, so I just change this attribute to string "foo" and it just worked and never crash again.
Thanks! the information you provided helped me to get an insight into my problem.
|
67

This will help you!

AsNoTracking()

By default, EntityFramework tracks changes on entities that are queried and saves changes when you call SaveChanges() on the context.

If it is already tracking product:42, and you add or attach a product with the Id:42 that it hasn't seen, there is ambiguity as to which represents the source of truth.

AsNoTracking produces objects which are not added to the change tracking mechanism, which you should use if you aren't using the change tracking features, because it's faster and makes your intent more explicit.

Most often, this is a scope issue. You don't expect there to be something in the cache, but surprise, there is - usually because of some global variable or a context which was not disposed - Both very common. When you find the offending DbContext, either wrap it in a 'using' or add AsNoTracking.

What difference does .AsNoTracking() make?

1 Comment

You should not disable change tracking if you want to manipulate entity instances and persist those changes to the database using SaveChanges(). learn.microsoft.com/en-us/dotnet/api/…
30

In Dotnet 6 you can just add this to your dbcontext options in the program.cs file:

builder.Services.AddDbContext<AppDbContext>(options =>
{
    options.UseSqlServer(connectionString);
    options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
});

4 Comments

You could do this for a long time. But it's not a good idea. Usually you want tracking.
This works in dotnet 3.1 too.
Nice, I wish this was the default. More functional, less invisibly side-effecty.
When working with databases, avoid using QueryTrackingBehavior.NoTracking as a global behavior, especially when you need to write data. It is more suitable for read-only scenarios and should be used selectively. In the data access layer, you can apply AsNoTracking() specifically to certain operations by leveraging the Fluent API, ensuring it is used only where it makes sense, such as for queries where change tracking is unnecessary.
26

I ran into this issue, but my DbContext was already registered as Scoped. My issue was that a property was being tracked within a nested navigation property. Nulling that navigation property (leaving the foreign key) fixed this for me.

3 Comments

Thanks @Nicholas Smith, for me this solution also worked, however, thinking... wouldn't it be an Entity Framework bug?
Thanks, this helped me find my problem. I had 2 lines of EF queries. The two queries are querying different tables (so different EF entities), but one of the table has FK which makes EF adds a nested navigation property in EF. So basically the issue was that I accidentally ended up with double tracking because of nested navigation property. The solution for me was to change one of the 2 queries to AsNoTracking().
Thanks, I encountered a similar situation and resolved it by fetching the object again without its navigation properties.
17

Just like Rudi Visser suggested, you can face this issue when using one entity across multiple data contexts. In my case, it was something similar to this:

User user = await DataContext.Users.SingleOrDefaultAsync(u => u.Id == "SomeId");

// Switch to UserManager *_*
var res = await UserManager.ResetPasswordAsync(user, token, password); // Exception thrown

A simple solution would be to try to stick to one DataContext, because UserManager seems to do some attaching and detaching (maybe) in the background. For example:

User user = await UserManager.FindByIdAsync("SomeId");
var res = await UserManager.ResetPasswordAsync(user, token, password);

1 Comment

After 3 hours of debugging, came across your solution! In my case, I was using a user entity from a UserStore and was passing it to the UserManager's ResetPasswordAsync. The problem is solved after I use UserManager for both. Thanks, man! Really appreciate your help!
12

You need Detached Entry-

Entry<CustomerBaseInfo>(data).State = EntityState.Detached;

2 Comments

It works for me! In cases of updating we need put this statment BEFORE to change props.
I don't think you should set detached. This way, you're just hiding the problem.
4

I am experiencing with same problem and googled and here is my thought

Entity framework has change tracker and entities are stored and referenced in the change tracker using their primary key. More precisely, dbcontext has a secret dictionary and it only allow to store one object of same type and same primary key. It can not track two object of same type and same primary key. Here is my sample code.

var model = new EaEnrollment()
        {
            Id = 1,
            UserId = 2,
            AllocationType = "Individual",
            Status = "In Progress"
        };
        _repoEaEnrollment.Update(model);
        //here is the some other code that meets my businees requirement
        //and changes the status to Completed and trying to update type a

        model.Status = "Completed";
        _repoEaEnrollment.Update(model); // exception .ie. it can not track 
                                         //  two distinct  instance. They are distinct becuase  
                                         //they have same typeand same primary key

I solved by detaching first instance from change tracker. Here is the solution code..

 var model = new EaEnrollment()
        {
            Id = 1,
            UserId = 2,
            AllocationType = "Individual",
            Status = "In Progress"
        };
        _repoEaEnrollment.Update(model);
        _repoEaEnrollment.SaveChanges();
        //here is the some other code that meets my businees requirement
        //and changes the status to Completed and trying to update type a

        //detach first instance from change tracker
        _repoEaEnrollment.Detach(model);

        //Update again
        model.Status = "Completed";
        _repoEaEnrollment.Update(model); // no exception  

Comments

1

In my case I had composite keys (3 keys) in one table and in the configurations I only added 2 of the keys and missed the third one.

Once I added the third key this fixed the issue for me!

Comments

0

I was also facing the same issue. I am on .Net 6.

I was trying to get the entity and was trying to update in the same method. You can add AsNoTracking in your get query and Update like this:

public async Task<Student> GetStudentById(long id, long schoolId)
{
    return await _context.Students.AsNoTracking()
                .FirstOrDefaultAsync(student => student.Id == id && student.SchoolId== schoolId);
}

public async Task<long> UpdateStudent(Student student)
{
    long updatedStudentId = 0;
    var studentInDb = await GetStudentById(student.Id, student.SchoolId);
    if(studentInDb != null)
    {
        _context.Students.Update(student);                
        updatedStudentId = await _context.SaveChangesAsync();
    }
    return updatedStudentId;
}

Comments

-1

For me, the following has worked (in .net 6):

dbcontext.Remove(EntityInstance);
dbcontext.model.Update(EntityInstance);

the above has generated the update statement and ran successfully as expected.

the following also has worked:

dbcontext.model.Remove(EntityInstance);
dbcontext.model.Update(EntityInstance);

1 Comment

Trying whit this code var existingEntity = db.Inventario.Local.FirstOrDefault(e => e.Id == student.Id); if (existingEntity != null) { db.Entry(existingEntity).CurrentValues.SetValues(student); } else { db.Inventario.Update(student); } db.SaveChanges();

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.