首页 > 解决方案 > 查询未跟踪模型中的列表导致列表中的元素被跟踪

问题描述

我收到一条错误消息

附加类型为“Application.Models.DatabaseModels.Bar”的实体失败,因为同一类型的另一个实体已经具有相同的主键值。

我以前见过这个错误并且知道它正在发生,因为我试图将实例的状态设置为Bar已修改,而上下文已经在跟踪具有相同 ID 的实例。我感兴趣的是Bar在我尝试设置状态之前导致被跟踪的情况。

下面是两个代码块,除了在第二个块中添加了一行之外,它们在各方面都是相同的。第一个函数将正确运行,将状态更改为foo.PrimaryBar已修改,而第二个函数将抛出错误。

这工作正常:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(ViewModel viewModel)
{
    Foo foo = await _context.Foos.AsNoTracking().FirstOrDefaultAsync(f => f.Id == viewModel.FooId);
    Foo.Primary.Bar = _context.Bars.AsNoTracking().First(c => c.Id == viewModel.PrimaryBarId);

    _context.SetModified(foo.Primary);

    //code continues
}

这会引发错误:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(ViewModel viewModel)
{
    Foo foo = await _context.Foos.AsNoTracking().FirstOrDefaultAsync(f => f.Id == viewModel.FooId);
    Foo.Primary.Bar = _context.Bars.AsNoTracking().First(c => c.Id == viewModel.PrimaryBarId);

    //this appears to add the Bars in Foo to the context
    var test = foo.Bars.Where(c => c.Id != foo.Primary.Bar.Id);

    //this is where the error occurs now
    _context.SetModified(foo.Primary);

    //code continues
}

为情况提供上下文:

数据库模型

public class Foo
{
    public int Id { get; set; }

    [ForeignKey("Primary")]
    public int? PrimaryId { get; set; }
    public virtual Primary Primary { get; set; }

    public virtual List<Bar> Bars { get; set; }
}

public class Bar
{
    public int Id { get; set; }

    [ForeignKey("Foo")]
    public int? FooId { get; set; }
    public virtual Foo Foo { get; set; }
}

public class Primary
{
    [Key, ForeignKey("Foo")]
    public int FooId { get; set; }
    public virtual Foo Foo { get; set; }

    [ForeignKey("Bar")]
    public int? BarId { get; set; }
    public virtual Bar Bar { get; set; }
}

查看模型

public class ViewModel
{
    public int FooId { get; set; }
    public int? PrimaryBarId { get; set; }
}

语境

public class AppDbContext : DbContext
{
    public virtual DbSet<Foo>           Foos            { get; set; }
    public virtual DbSet<Bar>           Bars            { get; set; }
    public virtual DbSet<Primary>       PrimaryBars     { get; set; }


    public virtual void SetModified<T>(T entity) where T : class
    {
        Entry(entity).State = EntityState.Modified;
    }
}

问题

为什么该行var test = foo.Bars.Where(c => c.Id != foo.Primary.Bar.Id);会导致Bar's 被上下文跟踪,即使它foo本身设置为AsNoTracking()

我是否误解了这里发生的事情,是什么AsNoTracking(),或者这是实体框架本身的错误?

标签: c#.netentity-framework

解决方案


推荐阅读