更新实体的 EF Core 问题

EF Core issue with updating an entity

提问人:Mihai Dabiste 提问时间:11/1/2023 最后编辑:marc_sMihai Dabiste 更新时间:11/1/2023 访问量:40

问:

我有一个通用存储库,其中包含以下两种方法:

public virtual async Task<T> GetById(TId id, CancellationToken cancellationToken = default)
{
    string key = GetCacheKeyById(id);
    return await base.GetFromCache(key,
            async () => { return await _dbContext.Set<T>().FindAsync(id); },
            cancellationToken: cancellationToken);
}

public virtual void Update(T entity)
{
    var key = GetCacheKeyById(_dbContext.GetPrimaryKey<TId>(entity));
    _dbContext.Set<T>().Update(entity);
    DeleteFromCache(key);
}

当我尝试更新实体时,我遇到了问题。

我的问题是,因为在验证层上,我调用了检索实体的方法,所以它被保存在缓存中。GetById

稍后,在业务层中,我再次调用以获取需要更新的实体,在其上设置一些属性,然后调用 .GetByIdUpdate

这会引发异常,并显示以下消息:

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

这似乎很公平,因为我正在更新的实体是从缓存中读取的,而不是被跟踪的实体。

现在我正在考虑向不从缓存中读取并直接从中获取实体添加一个可选参数,这应该为我提供跟踪的实体并且应该有效,但它似乎很丑陋。的作用域是,因此它在验证器和业务层中是同一个实例。GetByIddbContextdbContext

有没有更好/更清洁的方法来解决这个问题?

asp.net entity-framework .net-core entity-framework-core

评论

0赞 Guru Stron 11/1/2023
什么?你试过吗?GetPrimaryKey_dbContext.AsNoTracking().GetPrimaryKey<TId>(entity)
0赞 Mihai Dabiste 11/1/2023
GetPrimaryKey 是一种获取 PK 的方法,这样我就可以在更新时使缓存失效。基本上,我对 GetById() 进行了两次调用,并更新了第二次调用结果的值。第一次调用 GetById() 将从 dbContext 获取实体。第二次调用 GetById() 将从缓存中获取实体。当我更新第二次调用的结果时,我收到此错误(无法跟踪实体类型“entity”的实例,因为已经跟踪了具有相同 {'Id'} 键值的另一个实例。
0赞 Svyatoslav Danyliv 11/1/2023
使用以下命令代替:FindAsyncreturn await _dbContext.Set<T>().AsNoTracking().FirstOrDefaultAsync(e => e.Id == id)
0赞 Mihai Dabiste 11/1/2023
我想到了这一点,但我的存储库是通用的,有些实体有一个复合 PK,所以我不能做 e.Id
1赞 Svyatoslav Danyliv 11/1/2023
这是通用存储库的问题 - 引入了复杂性和新错误。我建议使用我的函数UpdateSafe,它负责处理重复项。ChangeTracker

答: 暂无答案