EF:无法跟踪实体类型X的实例,因为已经跟踪了具有相同键的该类型的另一个实例 [英] EF: The instance of entity type X cannot be tracked because another instance of this type with the same key is already being tracked

查看:590
本文介绍了EF:无法跟踪实体类型X的实例,因为已经跟踪了具有相同键的该类型的另一个实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在通过http请求以Json格式发送用户实体,如下所示:

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}}

而我的控制器(在 EF核心中)则是这样处理的:

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();
        }
    }
}

但是行Context.AccessTokens.Remove(accessTokenEntity);抛出此异常:

类型为"System.InvalidOperationException"的异常发生在 Microsoft.EntityFrameworkCore.dll,但未在用户代码中处理

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

其他信息:实体类型"AccessToken"的实例 无法跟踪,因为此类型的另一个实例具有相同的 密钥已被跟踪.添加新实体时,对于大多数关键 如果没有设置键,则将创建一个唯一的临时键值 (即,如果为key属性分配了其类型的默认值). 如果要为新实体明确设置键值,请确保它们 不要与现有实体或生成的临时值冲突 对于其他新实体.附加现有实体时,请确保 只有一个具有给定键值的实体实例附加到 上下文.

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.

除了相同的例外,我还尝试直接从userEntity访问AccessToken导航属性.

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

这是我的UnitOfWork初始化:

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();
}

我的CustomBdContext:

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

用户:

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

    public virtual AccessToken AccessToken { get; set; }
}

AccessToken:

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..

推荐答案

看来EF已经在跟踪user和其中的AccessToken.因此,让我们尝试避免获取同一实体的另一个实例,并重用已经跟踪的实例.

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.

尝试

[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();
    }
}

或者尝试:

[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();
    }
}

这篇关于EF:无法跟踪实体类型X的实例,因为已经跟踪了具有相同键的该类型的另一个实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆