EF: The instance of entity type X cannot be tracked because another instance of this type with the same key is already being tracked

只愿长相守 提交于 2019-12-06 05:39:57

问题


I am sending a User entity in Json format in my http request like this:

POST http://localhost:52054/api/Authentication/DeleteAccessToken HTTP/1.1
Host: localhost:52054
Content-Type: application/json

{"id":1,"userName":"mnoureldin","accessToken":{"id":1,"token":"123ABC456EFG","userId":1}}

And my controller (in EF-core) handles that like this:

[HttpPost]
public IActionResult DeleteAccessToken([FromBody]User user)
{
    using (var Context = new UnitOfWork().Context)
    {
        var userEntity = Context.Users.Find(user.Id); // Get the real entity of the user received as json
        if (userEntity != null)
        {
            var accessTokenEntity = Context.AccessTokens.Find(userEntity.AccessToken.Id); // Find the entity of the accesstoken (I tried also directly by accessing the navigation property of user entity)
            Context.AccessTokens.Remove(accessTokenEntity);
            return Ok();
        }
        else
        {
            return Unauthorized();
        }
    }
}

But the line Context.AccessTokens.Remove(accessTokenEntity); throws this exception:

An exception of type 'System.InvalidOperationException' occurred in Microsoft.EntityFrameworkCore.dll but was not handled in user code

Additional information: The instance of entity type 'AccessToken' cannot be tracked because another instance of this type with the same key is already being tracked. When adding new entities, for most key types a unique temporary key value will be created if no key is set (i.e. if the key property is assigned the default value for its type). If you are explicitly setting key values for new entities, ensure they do not collide with existing entities or temporary values generated for other new entities. When attaching existing entities, ensure that only one entity instance with a given key value is attached to the context.

I tried also accessing the AccessToken navigation property directly from userEntity with the same exception.

Here is my UnitOfWork initialization:

public UnitOfWork()
{
    // Configure EF connection
    var optionsBuilder = new DbContextOptionsBuilder<CustomDbContext>();
    optionsBuilder
        .UseMySQL(@"server=192.168.1.35; port=3306; sslmode=none;
                    userid=root;
                    pwd=P@ssword;
                    database=dotnet;");

    Context = new CustomDbContext(optionsBuilder.Options);

    // Configure data loading method to explicit
    Context.AccessTokens.Load();
}

My CustomBdContext:

public class CustomDbContext : DbContext
{
    // Tell EF to map the entities to tables
    public DbSet<User> Users { get; set; }
    public DbSet<AccessToken> AccessTokens { get; set; }

    public CustomDbContext(DbContextOptions options) : base(options)
    {
    }
}

I have the following simple data model with one to one relationship:

User ----- AccessToken

User:

public class User
{
    public int Id { get; set; }
    public string UserName { get; set; }

    public virtual AccessToken AccessToken { get; set; }
}

AccessToken:

public class AccessToken
{
    public int Id { get; set; }
    public string Token { get; set; }

    [ForeignKey("User"), Required]
    public int UserId { get; set; }
    public virtual User User { get; set; }
}

Could someone help me to solve that? I didn't understand what is exactly happening..


回答1:


It appears that EF is already tracking user and the AccessToken in it. So, let's try to avoid getting another instance of the same entity and reuse the already tracked one.

Try

[HttpPost]
public IActionResult DeleteAccessToken([FromBody]User user)
{
    // Requires System.Linq
    if (Context.Users.Any(u => u.Id == user.Id))
    {
        var accessTokenEntity = Context.AccessTokens.Find(user.AccessToken.Id); // Find the entity of the accesstoken (I tried also directly by accessing the navigation property of user entity)
        Context.AccessTokens.Remove(accessTokenEntity);

        // NOTE: You re not saving?
        return Ok();
    }
    else
    {
        return Unauthorized();
    }
}

Alternatively try:

[HttpPost]
public IActionResult DeleteAccessToken([FromBody]User user)
{
    if (Context.Users.Any(u => u.Id == user.Id))
    {
        Context.AccessTokens.Remove(user.AccessToken);
        return Ok();
    }
    else
    {
        return Unauthorized();
    }
}



回答2:


try replace this line:

var accessTokenEntity = Context.AccessTokens.Find(userEntity.AccessToken.Id);

to:

var accessTokenEntity = Context.AccessTokens.AsNoTracking().Find(userEntity.AccessToken.Id);


来源:https://stackoverflow.com/questions/42607030/ef-the-instance-of-entity-type-x-cannot-be-tracked-because-another-instance-of

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!