Search code examples
asp.net-coreentity-framework-corerepository-patternunit-of-work

EF Core 6 - The instance of entity type 'AppCase' cannot be tracked because another instance with the same key value for {} is already being tracked


I'm using ASP.NET Core 6, and EF Core 6, and Repository/UnitOfWork pattern. I have some trouble with my project, The error "The instance of entity type 'AppCase' cannot be tracked because another instance with the same key value for {} is already being tracked" have throwed when I call UpdateAsync in Repository. I think i know the issue description, and I used AsNoTracking() but the issue can't have been solved yet. How can I solve it, please.

Thanks for your support and sorry for my bad English!

Here is my source code:

    //MicroOrderBusiness.cs
    public async Task<dynamic> CreateOrder(MicroOrderRequest requsetObject, string caseNo)
    {
        string processCode = "CEC1D433-C376-498B-8A80-B23DC3772024";
        var caseModel = await _appCaseBusiness.PrepareAppCase(processCode, caseNo);
        if (caseModel == null)
            throw new Exception("Create request faield!");
        var appCaseEntity = await _appCaseBusiness.AddNewCase(caseModel); // => Add new Case by using EF 6 Core via Repository and UnitOfWork**
        if (appCaseEntity == null)
            throw new Exception("Adding faield!");
        var taskResponse = await _processTaskBusiness.ExecuteTask<MicroOrderRequest>(caseModel.FirstTaskCode, requsetObject);
        if (Equals(taskResponse, null))
            throw new Exception("Response task is not found!");
        caseModel.CaseObjects.Add(taskResponse);
        // Update case state
        appCaseEntity.State = STATE.DONE;
        appCaseEntity.CaseObject = JsonConvert.SerializeObject(appCase.CaseObjects);
        var updateCase = await _appCaseRepository.UpdateAsync(appCaseEntity); // => Error throw here**
        if (updateCase == null)
            throw new Exception($"Update state case faiedl!");
        return caseModel;
    }

    //Program.cs
    builder.Services.AddDbContext<AppDbContext>(options =>
                    options.UseOracle(connectionString,
                    o => o.MigrationsAssembly(typeof(AppDbContext)
                    .Assembly.FullName)
                    .UseOracleSQLCompatibility("12")));
    builder.Services.AddScoped(typeof(IUnitOfWork), typeof(AppDbContext));

Solution

  • The error has been explained in the document:https://learn.microsoft.com/en-us/ef/core/change-tracking/identity-resolution#attaching-a-serialized-graph

    I checked your codes, I think the error may caused by:

    tracking a serialized graph of entities

    appCaseEntity.CaseObject = JsonConvert.SerializeObject(appCase.CaseObjects);
            var updateCase = await _appCaseRepository.UpdateAsync(appCaseEntity); // => Error throw here**
    

    You could learn more details and found the solution in this part

    reusing a DbContext instance for multiple units-of-work

    var appCaseEntity = await _appCaseBusiness.AddNewCase(caseModel);
    ........
    var updateCase = await _appCaseRepository.UpdateAsync(appCaseEntity);
    

    You registed the dbcontext as below(the lifetime is scoped by default):

    builder.Services.AddDbContext<AppDbContext>(options =>
                        options.UseOracle(connectionString,
                        o => o.MigrationsAssembly(typeof(AppDbContext)
                        .Assembly.FullName)
                        .UseOracleSQLCompatibility("12")));
    

    You could try to set the lifetime with Trasident or Use DbContextFactory to create different instance in different units of work

    builder.Services.AddDbContext<AppDbContext>((options=>........),ServiceLifetime.Transient)
    

    Check this document about using DbContextFactory

    If you have further issue on this case,please provide the minimal codes that could reproduce the error