EF:エンティティタイプXのインスタンスは、同じキーを持つこのタイプの別のインスタンスがすでに追跡されているため追跡できません

asp.net-core asp.net-mvc c# entity-framework-core

質問

私はこのようにhttpリクエストでJson形式のUserエンティティを送信しています:

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-core )は次のように処理します:

[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);この例外をスローします。

Microsoft.EntityFrameworkCore.dllで 'System.InvalidOperationException'タイプの例外が発生しましたが、ユーザーコードで処理されませんでした

追加情報:エンティティタイプ 'AccessToken'のインスタンスは、同じキーを持つこのタイプの別のインスタンスがすでに追跡されているため追跡できません。新しいエンティティを追加するとき、ほとんどのキータイプに対して、キーが設定されていない場合(つまり、キープロパティにそのタイプのデフォルト値が割り当てられている場合)、一意の一時キー値が作成されます。新しいエンティティのキ​​ー値を明示的に設定する場合は、既存のエンティティや他の新しいエンティティ用に生成された一時的な値と衝突しないようにしてください。既存のエンティティをアタッチする場合は、指定されたキー値を持つエンティティインスタンスが1つだけコンテキストにアタッチされていることを確認します。

同じ例外を指定してuserEntityから直接AccessTokenナビゲーションプロパティにアクセスしようとしました。

私のUnitOfWorkの初期化は次のとおりです:

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:

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

私は、 1対1の関係を持つ次の単純なデータモデルを持っています。

User ----- AccessToken

ユーザー:

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

    public virtual AccessToken AccessToken { get; set; }
}

アクセストークン:

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

誰かが私にそれを解決する手助けをすることができますか?私は正確に何が起こっているのか分からなかった。

人気のある回答

EFは既にuserとその中のAccessToken追跡しているようです。したがって、同じエンティティの別のインスタンスを取得して、すでに追跡されているインスタンスを再利用しないようにしましょう。

試す

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


Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ