Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

一个上下文同时跟踪两个相同的实体 #739

Open
cc3w opened this issue Oct 28, 2024 · 2 comments
Open

一个上下文同时跟踪两个相同的实体 #739

cc3w opened this issue Oct 28, 2024 · 2 comments
Assignees

Comments

@cc3w
Copy link

cc3w commented Oct 28, 2024

Description

在更新前将实体的状态设置为Detached再更新,不报错,但是数据库没有更新。另说明还有一种情况,当结合Masa blazor时,在前端页面同时更新同一条记录也是会报同样的错误。但是单纯使用swagger测试并不会。
参考代码如下:
public async Task GetGenerateCodeAsync(AllMapTable mapTable)
{
Guid? tid = null;
//自动插入mapTable表
var table = await _mapTableRepository.FindAsync(t => t.EnTableName.Equals(mapTable));
if (table == null)
{
var description = EnumDescription.GetDescriptionAttribute(mapTable);
if (description == null)
{
throw new UserFriendlyException("获取枚举上的Description失败");
}
var command = new CreateMapTableCommand(description, mapTable.ToString());
await _eventBus.PublishAsync(command);
tid = command.Id;
}
await _codingRuleInfoRepository.GenerateCode(mapTable);

    var tt = await _codingRuleInfoRepository.FindAsync(t => t.MapTableId == (Guid)tid);

    tt.CurrentValue = 5;

    await _codingRuleInfoRepository.UpdateAsync(tt);

    return "111";

}
报错如下:System.InvalidOperationException: The instance of entity type 'CodingRuleInfo' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.

at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap1.ThrowIdentityConflict(InternalEntityEntry entry) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap1.Add(TKey key, InternalEntityEntry entry, Boolean updateDuplicate)···

.NET version

No response

MASA Framework version

No response

@Qinyouzeng
Copy link
Contributor

Qinyouzeng commented Oct 29, 2024

你好:
1、 你附加的源码尽量完整些,异常信息页尽量完整的贴出来;
2、 _在更新前将实体的状态设置为Detached再更新,不报错,但是数据库没有更新_这个问题,在代码里面没有反馈,也不好判断是哪里的问题;
3、_在前端页面同时更新同一条记录也是会报同样的错误。但是单纯使用swagger测试并不会_据此分析,应该跟你的服务对象周期使用有关,通过依赖关系注入进行参数绑定,IEventBus对象必须在接口方法上进行绑定(每次调用改接口,就会创建一次新的类型对象),不能在controller的构造方法里面绑定(此时绑定,该对象为应用程序存在期间一直存在的对象)。
这里得IEventBus对象注入,可以这么用

...

public Task AddAsync([FromServices] IEventBus eventBus, Dto dto)
{
      var command=new AddCommand(dto);
      return eventBus.PublishAsync(command);
}

...

@cc3w
Copy link
Author

cc3w commented Oct 29, 2024

十分感谢您的解答!!
好的,下面是简化业务逻辑举个示例

[Route("/API/[controller]/[action]")]
[ApiController]
[Authorize]
public class CodingRuleInfoService : ControllerBase
{
    private readonly IEventBus _eventBus;
    private readonly ICodingRuleInfoRepository _codingRuleInfoRepository;
    private readonly IMapTableRepository _mapTableRepository;
 public CodingRuleInfoService(ICodingRuleInfoRepository codingRuleInfoRepository, IMapTableRepository mapTableRepository, IEventBus eventBus)
 {
     _codingRuleInfoRepository = codingRuleInfoRepository;
     _mapTableRepository = mapTableRepository;
     _eventBus = eventBus;
 }
     [HttpGet]
    [AllowAnonymous]
    public async Task<string> GetGenerateCodeAsync([FromServices] IEventBus eventBus, AllMapTable mapTable)
    {

        var description = EnumDescription.GetDescriptionAttribute(mapTable);
        var command = new CreateMapTableCommand(description, mapTable.ToString());
        await eventBus.PublishAsync(command);


        await _codingRuleInfoRepository.GenerateCode(mapTable);

        return "1111";
    }
}

一开始使用的是_eventBus,后来听了您的建议使用[FromServices] IEventBus eventBus,结果是一样的;
仓储接口层

public interface ICodingRuleInfoRepository : IRepository<CodingRuleInfo>
{
    /// <summary>
    /// 生成编码
    /// </summary>
    /// <param name="table"></param>
    /// <returns></returns>
    Task<string> GenerateCode(AllMapTable table);
}

仓储实现层

public class CodingRuleInfoRepository : Repository<PlatformDbContext, CodingRuleInfo>, ICodingRuleInfoRepository
{
    private readonly PlatformDbContext _PlatformDbContext;
    public CodingRuleInfoRepository(PlatformDbContext PlatformDbContext, IUnitOfWork unitOfWork, IRepository<MapTable> mapTableRepository) : base(PlatformDbContext, unitOfWork)
    {
        _PlatformDbContext = PlatformDbContext;
    }

    public async Task<string> GenerateCode(AllMapTable table)
    {

        var entity = await _PlatformDbContext.Set<MapTable>().FirstOrDefaultAsync(t => t.EnTableName.Equals(table.ToString()));

        //var entityKey = entity.GetKeys().First();
        //var existingEntity = _PlatformDbContext.ChangeTracker.Entries<MapTable>().FirstOrDefault(e =>
        //{
        //    var entity = e.Entity.GetKeys().First();
        //    return entity.Name.Equals(entityKey.Name) && entity.Value.Equals(entity.Value);

        //})?.Entity;
        //if (existingEntity != null)
        //{
        //    _PlatformDbContext.Entry(existingEntity).State = Microsoft.EntityFrameworkCore.EntityState.Detached;
        //}

        entity.Remark = "2222";
        _PlatformDbContext.Set<MapTable>().Update(entity);

        return "2222";
    }
}

仓储实现层注释的代码放开,不会报错,但是数据库没有更新Remark字段
报错如下:

System.InvalidOperationException: The instance of entity type 'MapTable' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.ThrowIdentityConflict(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(TKey key, InternalEntityEntry entry, Boolean updateDuplicate)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTracking(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges, Boolean modifyProperties)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.PaintAction(EntityEntryGraphNode`1 node)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph[TState](EntityEntryGraphNode`1 node, Func`2 handleNode)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.AttachGraph(InternalEntityEntry rootEntry, EntityState targetState, EntityState storeGeneratedWithKeySetTargetState, Boolean forceStateWhenUnknownKey)
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.Update(TEntity entity)
   at MOM.Services.Platform.Infrastructure.Repositories.CodingModel.CodingRuleInfoRepository.GenerateCode(AllMapTable table) in D:\MyCC\codes\asuneast\MOM20241029\src\Services\MOM.Services.Platform\Infrastructure\Repositories\CodingModel\CodingRuleInfoRepository.cs:line 35
   at MOM.Services.Platform.Controllers.Setting.CodingRuleInfoService.GetGenerateCodeAsync(IEventBus eventBus, AllMapTable mapTable) in D:\MyCC\codes\asuneast\MOM20241029\src\Services\MOM.Services.Platform\Controllers\Setting\CodingRuleInfoService.cs:line 81
   at lambda_method112(Closure , Object )
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
   at Masa.Contrib.Isolation.Middleware.IsolationMiddleware.InvokeAsync(HttpContext httpContext, IEnumerable`1 middlewares)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

HEADERS
=======
Accept: text/plain
Connection: keep-alive
Host: localhost:5259
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: zh-CN,zh;q=0.9
Referer: http://localhost:5259/swagger/index.html
sec-ch-ua: "Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants