我将在HTTP请求中以Json格式发送一个用户实体,如下所示:
但是这行代码
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);
抛出了以下异常:
类型为“System.InvalidOperationException”的异常在 Microsoft.EntityFrameworkCore.dll 中发生,但未在用户代码中处理。
其他信息:实体类型“AccessToken”的实例无法被跟踪,因为已经有另一个具有相同键值的该类型实例正在被跟踪。对于大多数键类型,如果没有设置键(即如果为键属性分配其类型的默认值),则将创建唯一的临时键值来添加新实体。如果您明确为新实体设置键值,请确保它们不会与现有实体或为其他新实体生成的临时值发生冲突。当附加现有实体时,请确保只有一个具有给定键值的实体实例附加到上下文。
我还尝试从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)
{
}
}
我有一个简单的数据模型,它包含一对一关系:
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; }
}
有人能帮我解决这个问题吗?我不明白到底发生了什么。
Context.AccessTokens.Load();
似乎很奇怪,但这仍然无法解释该错误。当前可见的代码似乎没有导致任何附加实体的重复。Find
始终会首先查找已附加的实体。 - Gert Arnoldinclude
吗? - Mohammed NoureldinFind
、LINQ还是Load
,都会存储在上下文的缓存中,并跟踪其更改(除非您主动禁用跟踪)。上下文是一个身份映射,因此只能跟踪每个实体的一个副本。当EF获取实体时,它会自行处理这个身份规则。手动将实体附加到上下文(例如通过添加它们)可能会导致问题。但在可见代码中似乎并没有发生这种情况。也许这可以给您一个进一步查找的提示。 - Gert Arnold