【发布时间】:2017-03-05 10:08:53
【问题描述】:
我在我的 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在哪里初始化? -
@GertArnold 是的,通过调试从数据库中获取
userEntity和accessTokenEntity变量。 -
这不是我的问题的答案。你在哪里初始化
Context本身?在查看此“已被跟踪”错误时,这始终是信息的第一个重要部分。 -
我仍然觉得我们没有看到全貌。但我会开始将其建模为真正的 1:1 关系(即 AccessToken 的 PK 也是它对用户的 FK)。
-
EF 通过
Find、LINQ 或Load从数据库中获取的任何对象都存储在上下文的缓存中并跟踪更改(除非您主动禁用跟踪)。上下文是一个身份映射,因此每个实体只能跟踪一个副本。当 EF 获取实体时,它将自行处理此身份规则。手动将实体附加到上下文(例如通过添加它们)可能会导致您的问题。但这似乎并没有在可见代码中发生。也许这会提示您在哪里进一步寻找。
标签: c# asp.net-mvc asp.net-core entity-framework-core