c# - 无法跟踪实体类型 ''的实例

标签 c# entity-framework asp.net-core single-page-application progressive-web-apps

我正在发送授权请求,在授权的方法 Controller 中,我尝试更新已通过授权的用户的实体,但出现错误:

无法跟踪实体类型“SUsers”的实例,因为已跟踪具有键值“{Id: 1}”的另一个实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。

使用的堆栈

asp core 2.2、spa、vue、pwa、jwt、automapper 8.8.4、Microsoft.EntityFrameworkCore 2.2.4

版本

  • 网络核心2.2
  • Microsoft.EntityFrameworkCore 2.2.4
  • Microsoft.EntityFrameworkCore.InMemory 2.2.4
  • Microsoft.EntityFrameworkCore.Design 2.2.4
  • Microsoft.EntityFrameworkCore.SqlServer 2.2.4

0,DI

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

}

1。 API Controller

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

2。服务

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

}

3。 repo 协议(protocol)

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

4。工作单元

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

重现步骤

  1. 克隆https://github.com/UseMuse/asp-core-2.2-clean.git
  2. 构建解决方案,启动 PWSPA.WEB 项目
  3. 登录:登录 - 访客,通过 - 任何图表
  4. 在 API Controller AuthController 中,方法 Login,异常行 90

预期行为:

实体更新

错误消息

无法跟踪实体类型“SUsers”的实例,因为已跟踪具有键值“{Id: 1}”的另一个实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。

堆栈跟踪

位于 Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap1.ThrowIdentityConflict(InternalEntityEntry 条目) 在 Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap1.Add(TKey 键,InternalEntityEntry 条目, bool updateDuplicate) 在 Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTracking(InternalEntityEntry 条目) 在Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState,EntityState newState, bool acceptChanges) 在 Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.PaintAction(EntityEntryGraphNode 节点, bool 力) 在 Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph[TState](EntityEntryGraphNode 节点,TState 状态,Func3 handleNode) 在 Microsoft.EntityFrameworkCore.DbContext.SetEntityState[TEntity](TEntity 实体,EntityState 实体状态) 在 D:\repos\asp-core-2.2-clean2\PWSPA.DAL\Repositories\GenericRepository.cs 中的 PWSPA.DAL.Repositories.GenericRepository1.Update(TEntity Updated):第 99 行 在 D:\repos\asp-core-2.2-clean2\PWSPA.BLL\Services\ServiceBase.cs 中的 PWSPA.BLL.Services.ServiceBase`2.Update(TModelDTOEntityDto):第 208 行 在 D:\repos\asp-core-2.2-clean2\PWSPA.WEB\API\AuthController.cs 中的 PWSPA.API.Controllers.AuthController.Login(RequestTokenApiModel 模型):第 90 行

最佳答案

您在这里犯了一个菜鸟错误,本质上只是转储您能想到的所有信息,但具有讽刺意味的是,您错过了唯一真正重要的部分:_iAuthService 背后的代码。仅发布与问题直接相关的代码。如果我们需要其他东西,我们可以随时提出要求。并且,在这方面,发布与该问题直接相关的所有代码。如果错误是由您编写的自定义服务类引起的,请发布该服务类。

也就是说,您遇到的错误可归结为以下情况。在某些时候,您查询一个实体,该实体会将其添加到上下文的对象跟踪中。然后,您稍后尝试更新该实体的非跟踪版本,而不是您查询的版本。从模型绑定(bind)器接收它(即它是操作上的参数),使用 new 实例化它,或者简单地使用上下文的不同实例来检索它(并保存它)可能会发生这种情况到另一个实例)。

根据您提供的代码,我的钱在最后一个。您可能没有在服务类中正确处理上下文,并且您正在从上下文的一个实例获取要修改的实体,并尝试使用上下文的不同实例来更新它。您的上下文应该始终被注入(inject),以确保您在整个生命周期(请求)中始终使用相同的实例。换句话说,如果您正在执行 using (var context = new MyContext()) 或任何 new MyContext(),那就是您的问题。

关于c# - 无法跟踪实体类型 ''的实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56582494/

相关文章:

entity-framework - 我可以在 Entity Framework 中混合使用每个层次结构的表和每个类型的表吗?

asp.net - Entity Framework CTP5,代码优先。可选导航属性

每个请求的 ASP.NET 5 (VNext) Autofac 实例

c# - 无法在服务结构中使用 DNS 与服务通信

c# - nant脚本c#编译错误

c# - "wrong"单元格上的 LinqToExcel 异常处理

c# - 如果仅更改内部版本号或修订版号,则定位 GAC 程序集

c# - 如何使用 Rx 定期执行代码直到第一次成功执行?

c# - 使用迁移删除/添加列的 "defaultvaluesql"

.net - asp.net core 在两列上创建约束,其中一列是另一个实体