无法跟踪实体类型 'x' 的实例,因为已跟踪具有键值“{Id: 6}”的另一个实例
The instance of entity type 'x' cannot be tracked because another instance with the key value '{Id: 6}' is already being tracked
我正在做一个 asp .netcore 6.0 干净架构项目。
当我尝试更新站点时,出现此错误,
System.InvalidOperationException: 无法跟踪实体类型 'SiteCode' 的实例,因为另一个具有键值 '{Id: 6}' 的实例已经被跟踪。附加现有实体时,确保只附加一个具有给定键值的实体实例。
在我们使用服务之前,同样的代码在那里运行良好。现在我们转向干净的架构(CQRS 和 Mediatr)。我使用了相同的更新代码,但出现此错误。
.AsNoTracking()
我试过
var result = await _DbContext.SiteCodes.FindAsync(request.Id).AsNoTracking();
这一行,
但是出现错误,
'ValueTask<SiteCode?>' does not contain a definition for 'AsNoTracking' and no accessible extension method 'AsNoTracking' accepting a first argument of type 'ValueTask<SiteCode?>' could be found (are you missing a using directive or an assembly reference?) [Application]
这是我的代码
UpdateSiteCommandHandler.cs
public async Task<SiteCode> Handle(UpdateSiteCommand request, CancellationToken cancellationToken)
{
var result = _mapper.Map<SiteCode>(request);
_DbContext.SiteCodes.Update(result); // goes to exception after this line
await _DbContext.SaveChangesAsync(cancellationToken);
return result;
}
GetSiteByIdQueryHandler.cs
public async Task<SiteCode> Handle(GetSiteByIdQuery request, CancellationToken cancellationToken)
{
var result = await _DbContext.SiteCodes.FindAsync(request.Id);
if (result == null)
{
throw new NotFoundException(nameof(SiteCode), request.Id);
}
return result;
}
控制器
public async Task<IActionResult> Update(int id, [FromBody] UpdateSiteCommand command)
{
command.Id = id;
var siteCode = await _mediator.Send(new GetSiteByIdQuery(Id: id));
var result = await _mediator.Send(command);
return Ok(result);
}
DependencyInjection.cs
public static class DependencyInjection
{
public static IServiceCollection AddApplication(this IServiceCollection services)
{
services.AddAutoMapper(Assembly.GetExecutingAssembly());
services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
services.AddMediatR(Assembly.GetExecutingAssembly());
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(PerformanceBehaviour<,>)); // I tried with AddScoped() But not work
return services;
}
}
在 DbContext 中
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
{
var entries = ChangeTracker
.Entries()
.Where(e => e.Entity is AuditableEntity && (
e.State == EntityState.Added
|| e.State == EntityState.Modified));
foreach (var entityEntry in entries)
{
if (entityEntry.State == EntityState.Added)
{
((AuditableEntity)entityEntry.Entity).CreatedAt = DateTime.UtcNow;
((AuditableEntity)entityEntry.Entity).CreatedBy = _httpContextAccessor?.HttpContext?.User?.Identity?.Name ?? null;
}
else
{
Entry((AuditableEntity)entityEntry.Entity).Property(p => p.CreatedAt).IsModified = false;
Entry((AuditableEntity)entityEntry.Entity).Property(p => p.CreatedBy).IsModified = false;
}
((AuditableEntity)entityEntry.Entity).ModifiedAt = DateTime.UtcNow;
((AuditableEntity)entityEntry.Entity).ModifiedBy = _httpContextAccessor?.HttpContext?.User?.Identity?.Name ?? null;
}
var result = await base.SaveChangesAsync(cancellationToken)
return result;
}
有人知道如何解决这个问题吗?
尝试在 Handler (GetSiteByIdQueryHandler.cs) 中将 SiteCodes 之后的方法 AsNoTracking() 添加到您的查询中。
public async Task<SiteCode> Handle(GetSiteByIdQuery request, CancellationToken cancellationToken)
{
var result = await _DbContext.SiteCodes.AsNoTracking().FindAsync(request.Id);
if (result == null)
{
throw new NotFoundException(nameof(SiteCode), request.Id);
}
return result;
}
EF Core 使用 ChangeTracker 检测加载实体的变化,更好(不是更快)的解决方案是加载实体进行更新。
public async Task<SiteCode> Handle(UpdateSiteCommand request, CancellationToken cancellationToken)
{
// the following code will load entitiy if it is still not loaded.
var dbRequest = await _DbContext.SiteCodes.FindAsync(request.Id);
if (dbRequest == null)
throw new Exception("Not found");
_mapper.Map<SiteCode>(request, dbRequest);
await _DbContext.SaveChangesAsync(cancellationToken);
return result;
}
我正在做一个 asp .netcore 6.0 干净架构项目。
当我尝试更新站点时,出现此错误,
System.InvalidOperationException: 无法跟踪实体类型 'SiteCode' 的实例,因为另一个具有键值 '{Id: 6}' 的实例已经被跟踪。附加现有实体时,确保只附加一个具有给定键值的实体实例。
在我们使用服务之前,同样的代码在那里运行良好。现在我们转向干净的架构(CQRS 和 Mediatr)。我使用了相同的更新代码,但出现此错误。
.AsNoTracking()
我试过
var result = await _DbContext.SiteCodes.FindAsync(request.Id).AsNoTracking();
这一行,
但是出现错误,
'ValueTask<SiteCode?>' does not contain a definition for 'AsNoTracking' and no accessible extension method 'AsNoTracking' accepting a first argument of type 'ValueTask<SiteCode?>' could be found (are you missing a using directive or an assembly reference?) [Application]
这是我的代码
UpdateSiteCommandHandler.cs
public async Task<SiteCode> Handle(UpdateSiteCommand request, CancellationToken cancellationToken)
{
var result = _mapper.Map<SiteCode>(request);
_DbContext.SiteCodes.Update(result); // goes to exception after this line
await _DbContext.SaveChangesAsync(cancellationToken);
return result;
}
GetSiteByIdQueryHandler.cs
public async Task<SiteCode> Handle(GetSiteByIdQuery request, CancellationToken cancellationToken)
{
var result = await _DbContext.SiteCodes.FindAsync(request.Id);
if (result == null)
{
throw new NotFoundException(nameof(SiteCode), request.Id);
}
return result;
}
控制器
public async Task<IActionResult> Update(int id, [FromBody] UpdateSiteCommand command)
{
command.Id = id;
var siteCode = await _mediator.Send(new GetSiteByIdQuery(Id: id));
var result = await _mediator.Send(command);
return Ok(result);
}
DependencyInjection.cs
public static class DependencyInjection
{
public static IServiceCollection AddApplication(this IServiceCollection services)
{
services.AddAutoMapper(Assembly.GetExecutingAssembly());
services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
services.AddMediatR(Assembly.GetExecutingAssembly());
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(PerformanceBehaviour<,>)); // I tried with AddScoped() But not work
return services;
}
}
在 DbContext 中
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
{
var entries = ChangeTracker
.Entries()
.Where(e => e.Entity is AuditableEntity && (
e.State == EntityState.Added
|| e.State == EntityState.Modified));
foreach (var entityEntry in entries)
{
if (entityEntry.State == EntityState.Added)
{
((AuditableEntity)entityEntry.Entity).CreatedAt = DateTime.UtcNow;
((AuditableEntity)entityEntry.Entity).CreatedBy = _httpContextAccessor?.HttpContext?.User?.Identity?.Name ?? null;
}
else
{
Entry((AuditableEntity)entityEntry.Entity).Property(p => p.CreatedAt).IsModified = false;
Entry((AuditableEntity)entityEntry.Entity).Property(p => p.CreatedBy).IsModified = false;
}
((AuditableEntity)entityEntry.Entity).ModifiedAt = DateTime.UtcNow;
((AuditableEntity)entityEntry.Entity).ModifiedBy = _httpContextAccessor?.HttpContext?.User?.Identity?.Name ?? null;
}
var result = await base.SaveChangesAsync(cancellationToken)
return result;
}
有人知道如何解决这个问题吗?
尝试在 Handler (GetSiteByIdQueryHandler.cs) 中将 SiteCodes 之后的方法 AsNoTracking() 添加到您的查询中。
public async Task<SiteCode> Handle(GetSiteByIdQuery request, CancellationToken cancellationToken)
{
var result = await _DbContext.SiteCodes.AsNoTracking().FindAsync(request.Id);
if (result == null)
{
throw new NotFoundException(nameof(SiteCode), request.Id);
}
return result;
}
EF Core 使用 ChangeTracker 检测加载实体的变化,更好(不是更快)的解决方案是加载实体进行更新。
public async Task<SiteCode> Handle(UpdateSiteCommand request, CancellationToken cancellationToken)
{
// the following code will load entitiy if it is still not loaded.
var dbRequest = await _DbContext.SiteCodes.FindAsync(request.Id);
if (dbRequest == null)
throw new Exception("Not found");
_mapper.Map<SiteCode>(request, dbRequest);
await _DbContext.SaveChangesAsync(cancellationToken);
return result;
}