You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用xUnit编写单元测试时遇「实体类型实例无法被跟踪」错误

解决EF Core单元测试中的实体跟踪冲突错误

错误原因

测试中复用了同一个ApplicationDbContext实例:先通过它添加测试数据并执行SaveChanges,此时这些Book实体仍被上下文的跟踪器记录。当调用Update方法时,传入的newBook与上下文已跟踪的某一Book实体主键重复,此时尝试将newBook标记为修改状态,EF Core会因同一主键的实体已被跟踪而抛出"The instance of entity type cannot be tracked.."错误。

注意:生产环境中通常每个请求对应一个独立的DbContext实例,因此不会出现该冲突,但单元测试中复用实例就会触发问题。

解决方法

方法1:添加数据后解除实体跟踪

在测试的Arrange阶段,执行SaveChanges后手动解除所有实体的跟踪状态,让上下文不再持有这些实体的跟踪信息:

[Fact]
public void UpdateBook()
{
    /* Arrange */

    var newBook = BookMockData.UpdateBook();
    _context.Books.AddRange(BookMockData.GetBooks());
    _context.SaveChanges();

    // 解除所有实体的跟踪,避免后续Update时冲突
    foreach (var entry in _context.ChangeTracker.Entries())
    {
        entry.State = EntityState.Detached;
    }

    var sut = new BookRepository(_context);

    /* Assert & Act */
    
    FluentActions.Invoking(() => sut.Update(newBook)).Should().NotThrow();
}

方法2:使用独立DbContext实例执行Update

模拟生产环境的上下文隔离,用一个DbContext添加测试数据,再创建新的DbContext实例用于仓库的Update操作:

[Fact]
public void UpdateBook()
{
    /* Arrange */

    var newBook = BookMockData.UpdateBook();
    var options = _context.Options; // 获取上下文配置

    // 用独立上下文添加测试数据
    using (var addContext = new ApplicationDbContext(options))
    {
        addContext.Books.AddRange(BookMockData.GetBooks());
        addContext.SaveChanges();
    }

    // 新上下文用于执行Update操作
    var sutContext = new ApplicationDbContext(options);
    var sut = new BookRepository(sutContext);

    /* Assert & Act */
    
    FluentActions.Invoking(() => sut.Update(newBook)).Should().NotThrow();
}

方法3:调整仓库Update逻辑(可选)

修改仓库的Update方法,避免直接使用传入的实体,而是将属性值映射到查询到的实体上,再执行保存:

public override void Update(Book entity)
{
    var result = _context.Books.AsNoTracking().SingleOrDefault(x => x.ProductId == entity.ProductId);

    if (result == null)
        throw new InvalidOperationException("Güncellemek istediğiniz kitap bulunamadı.");

    // 将传入实体的属性值映射到查询到的实体
    _context.Entry(result).CurrentValues.SetValues(entity);
    base.Save();
}

此方法无需修改测试代码,同时让Update逻辑更健壮,避免依赖传入实体的跟踪状态。

内容的提问来源于stack exchange,提问作者Oguz Akcay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 23:02:42