[英]The instance of entity type '' cannot be tracked
我正在發送授權請求,在用於授權的方法控制器中,我試圖為已通過授權的用戶更新實體,但出現錯誤:
無法跟蹤實體類型“ SUsers”的實例,因為已經跟蹤了另一個鍵值為“ {Id:1}”的實例。 附加現有實體時,請確保僅附加一個具有給定鍵值的實體實例。
asp core 2.2,spa,vue,pwa,jwt,automapper 8.8.4,Microsoft.EntityFrameworkCore 2.2.4
public static class StartupExtension
{
public static IServiceCollection AddDependencies(this IServiceCollection _iServiceCollection, IConfiguration AppConfiguration )
{
#region Data
string ids = System.Guid.NewGuid().ToString();
_iServiceCollection.AddDbContext<BaseDbContext, FakeDbContext>(opt =>
{
opt.UseInMemoryDatabase(ids);
});
_iServiceCollection.AddScoped<IBaseDbContext>(provider => provider.GetService<BaseDbContext>());
#endregion
#region AutoMapper
var config = new MapperConfiguration(cfg => {
cfg.AddMaps("PWSPA.WEB", "PWSPA.BLL");
});
config.AssertConfigurationIsValid();
#endregion
#region Repository
_iServiceCollection.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>));
_iServiceCollection.AddScoped<IUnitOfWork, UnitOfWork>();
#endregion
#region service
#region mapper service
_iServiceCollection.AddScoped(typeof(IGenericMapperService<,>), typeof(GenericMapperService<,>));
_iServiceCollection.AddScoped(typeof(IMapperService), typeof(MapperService));
#endregion
_iServiceCollection.AddScoped<IAuthService, AuthService>();
#endregion
return _iServiceCollection;
}
}
public class AuthController : BaseApiController
{
private readonly ILogger _log;
private readonly SecuritySettings _config;
private readonly IUserVerify _signInMgr;
private readonly IAuthService _iAuthService;
[AllowAnonymous]
[HttpPost("login")]
public IActionResult Login([FromBody] RequestTokenApiModel model)
{
try
{
SUsersDTO user = null;
user = _iAuthService.SingleOrDefault(u =>
u.WindowsLogin.ToLower() == "guest");
user.WindowsLogin = "guest";
/*
The instance of entity type 'SUsers' cannot be tracked
because another
instance with the key value '{Id: 1}' is already being
tracked. When
attaching existing entities, ensure that only one entity
instance with a
given key value is attached.
*/
countUpdate = _iAuthService.Update(user);
}
catch (ArgumentException ex)
{
return BadRequest(ex.Message);
}
catch (Exception ex)
{
_log.LogError(ex, ex.Message);
return StatusCode(500, ex.Message);
}
}
}
public class AuthService : ServiceBase<SUsers, SUsersDTO>, IAuthService
{
public AuthService(IUnitOfWork uow, IMapperService MapperService) : base(uow, MapperService)
{
Repository.Query().Include(u => u.Role).Load();
}
...
}
public class ServiceBase<TModel, TModelDTO> : IGenericService<TModelDTO> where TModel : class where TModelDTO : class
{
private readonly IUnitOfWork db;
private readonly IMapperService _MapService;
private readonly IGenericRepository<TModel> genericRepository;
private readonly IGenericMapperService<TModel, TModelDTO> genericMapService;
public ServiceBase(IUnitOfWork uow, IMapperService iMapperService)
{
_MapService = iMapperService;
db = uow;
genericRepository = uow.Repository<TModel>();
genericMapService = _MapService.Map<TModel, TModelDTO>();
}
protected virtual Type ObjectType => typeof(TModel);
protected virtual IGenericRepository<TModel> Repository => genericRepository;
protected virtual IMapperService MapService => _MapService;
protected virtual IGenericMapperService<TModel, TModelDTO> Map => genericMapService;
protected virtual IUnitOfWork Database => db;
...
public int Update(TModelDTO entityDto)
{
var entity = Map.For(entityDto);
return Repository.Update(entity);
}
}
public class GenericRepository<TEntity> :
IGenericRepository<TEntity> where TEntity : class
{
private readonly IBaseDbContext _context;
private readonly IUnitOfWork _unitOfWork;
private readonly string errorMessage = string.Empty;
public GenericRepository(IBaseDbContext context, IMapper _iMapper) //: base(context, _iMapper)
{
_context = context;
_unitOfWork = new UnitOfWork(context, _iMapper);
}
public Type ObjectType => typeof(TEntity);
protected virtual IBaseDbContext DbContext => _context;
protected virtual DbSet<TEntity> DbSet => _context.Set<TEntity>();
...
public int Update(TEntity updated)
{
if (updated == null)
{
return 0;
}
DbSet.Attach(updated);
_context.Entry(updated).State = EntityState.Modified;
return Save();
}
...
private int Save()
{
try
{
return _unitOfWork.Commit();
}
catch (DbUpdateException e)
{
throw new DbUpdateException(e.Message, e);
}
}
public class UnitOfWork : IUnitOfWork
{
private readonly IBaseDbContext _dbContext;
private readonly Dictionary<Type, object> _repositories = new Dictionary<Type, object>();
private readonly IMapper _iMapper;
public Dictionary<Type, object> Repositories
{
get => _repositories;
set => Repositories = value;
}
public UnitOfWork(IBaseDbContext dbContext, IMapper _iMapper)
{
_dbContext = dbContext;
this._iMapper = _iMapper;
}
public IGenericRepository<TEntity> Repository<TEntity>() where TEntity : class
{
if (Repositories.Keys.Contains(typeof(TEntity)))
{
return Repositories[typeof(TEntity)] as IGenericRepository<TEntity>;
}
IGenericRepository<TEntity> repo = new GenericRepository<TEntity>(_dbContext, _iMapper);
Repositories.Add(typeof(TEntity), repo);
return repo;
}
public EntityEntry<TEintity> Entry<TEintity>(TEintity entity) where TEintity : class
{
return _dbContext.Entry(entity);
}
...
}
public int Update(TEntity updated)
{
if (updated == null)
{
return 0;
}
/*
on line DbSet.Attach(updated) an exception occurs
*/
DbSet.Attach(updated);
_context.Entry(updated).State = EntityState.Modified;
return Save();
}
public int Update(TModelDTO entityDto)
{
var entity = Map.For(entityDto);
return Repository.Update(entity);
}
實體更新
無法跟蹤實體類型“ SUsers”的實例,因為已經跟蹤了另一個鍵值為“ {Id:1}”的實例。 附加現有實體時,請確保僅附加一個具有給定鍵值的實體實例。
在Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap 1.ThrowIdentityConflict(InternalEntityEntry entry) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap
處的1.ThrowIdentityConflict(InternalEntityEntry entry) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap
Microsoft的Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState,EntityState newState,Boolean acceptChanges)在Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.PaintAction(EntityEntryGraphNode節點,布爾值) EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph [TState]( 3 handleNode) at Microsoft.EntityFrameworkCore.DbContext.SetEntityState[TEntity](TEntity entity, EntityState entityState) at PWSPA.DAL.Repositories.GenericRepository
1上的EntityEntryGraphNode節點,TState狀態,Func 3 handleNode) at Microsoft.EntityFrameworkCore.DbContext.SetEntityState[TEntity](TEntity entity, EntityState entityState) at PWSPA.DAL.Repositories.GenericRepository
.Update(已更新TEntity) 在D:\\ repos \\ asp-中的D:\\ repos \\ asp-core-2.2-clean2 \\ PWSPA.DAL \\ Repositories \\ GenericRepository.cs:PWSPA.BLL.Services.ServiceBase`2.Update(TModelDTO entityDto)的第99行D:\\ repos \\ asp-core-2.2-clean2 \\ PWSPA.WEB \\中的PWSPA.API.Controllers.AuthController.Login(RequestTokenApiModel模型)處的core-2.2-clean2 \\ PWSPA.BLL \\ Services \\ ServiceBase.cs:第208行API \\ AuthController.cs:第90行
您在這里犯了一個新手錯誤,即本質上只是轉儲您可以想到的所有信息,但是,具有諷刺意味的是,您錯過了唯一真正重要的部分: _iAuthService
背后的代碼。 僅發布與問題直接相關的代碼。 如果我們需要其他東西,我們總是可以要求它。 並且,就此而言,發布與該問題直接相關的所有代碼。 如果錯誤是由於您編寫的自定義服務類引起的,請發布該服務類。
也就是說,您遇到的錯誤歸結為以下情況。 有時,您查詢一個實體,將其添加到上下文的對象跟蹤中。 然后,您稍后嘗試更新該實體的非跟蹤版本,而不是查詢的版本。 這可能是因為從模型綁定器接收到了它(即,這是動作的一個參數),實際上是使用new
實例化了它,或者只是使用了上下文的另一個實例來檢索它(並將其保存到另一個實例中)。
根據您提供的代碼,我的錢就放在最后一個。 您可能沒有在服務類中正確處理上下文,並且正在使實體從上下文的一個實例進行修改,並嘗試使用上下文的另一個實例進行更新。 應該始終注入上下文,以確保在整個生命周期(請求)中始終使用同一實例。 換句話說,如果您正在using (var context = new MyContext())
或實際上是任何new MyContext()
,那就是您的問題。
由於我使用automapper,因此我的問題已使用AutoMapper.Collection解決。
我的解決問題
//using AutoMapper;
//using AutoMapper.Configuration;
//using AutoMapper.EquivalencyExpression;
//using AutoMapper.Extensions.ExpressionMapping;
services.AddAutoMapper (assemblyes);
MapperConfigurationExpression configExpression = new MapperConfigurationExpression ();
configExpression.AddCollectionMappers ();
configExpression.AddExpressionMapping ();
configExpression.UseEntityFrameworkCoreModel <BaseDbContext> (services.BuildServiceProvider ().
CreateScope (). ServiceProvider);
configExpression.AddMaps (assemblyes);
Mapper.Initialize (configExpression);
Mapper.Configuration.AssertConfigurationIsValid ();
//using AutoMapper.EntityFrameworkCore;
//using Microsoft.EntityFrameworkCore;
public static class RepoExtensions
{
public static TModel InsertOrUpdate<TModel, TModelDto>(this IRepository repository, TModelDto modelDto) where TModel : BaseEntity where TModelDto :
BaseEntityDTO
{
TModel model = repository.DbSet<TModel>().Persist().InsertOrUpdate(modelDto);
repository.Save();
return model;
}
public static async Task<TModel> InsertOrUpdateAsync<TModel, TModelDto>(this IRepository repository, TModelDto modelDto) where TModel : BaseEntity where TModelDto :
BaseEntityDTO
{
TModel model = repository.DbSet<TModel>().Persist().InsertOrUpdate(modelDto);
await repository.SaveAsync();
return model;
}
}
之前
public int Update(TModelDTO entityDto) { var entity = Map.For(entityDto); return Repository.Update(entity); }
后
public TModel Update(TModelDTO entityDto)
{
return Repository.InsertOrUpdate<TModel, TModelDTO>(entityDto);
}
ps該示例引用的存儲庫未更新
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.