什么会导致DBSET持续存在的实体被分离



我正在使用实体框架核心来检索已经存储在数据库中的实体,但是根据我的操作方式,即使我'm根本不使用AsNoTracking

这些是用于建模数据库的类:

class AppDbContext : DbContext
{
    public DbSet<Thing> Thing { get; set; }
    protected override void OnConfiguring(DbContextOptionsBuilder options)
    {
        options.UseSqlServer("...");
    }
}
class Thing
{
    public int ThingId { get; set; }
    public string Name { get; set; }
}

以下是用于重现以分离状态检索实体的场景的类:

class Wrapper
{
    public Thing Thing { get; set; }
    public Wrapper(Thing t)
    {
        Thing = t;
    }
}

主要程序进行以下操作:

foreach (var wrapper in context.Thing.Select(a => new Wrapper(a)))
{
    Console.WriteLine(context.Entry(wrapper.Thing).State);
}
foreach (var thing in context.Thing.Select(a => a))
{
    Console.WriteLine(context.Entry(thing).State);
}

假设Thing表中有三行,输出将变为以下:

Detached
Detached
Detached
Unchanged
Unchanged
Unchanged

换句话说,如果检索到实体,则将实体分离,然后传递到Wrapper构造函数中,但会跟踪(以"未更改"状态),如果只是定期检索。

我的理解是,除非用AsNoTracking明确检索,否则已经持续到数据库的实体应始终以跟踪状态检索,那么什么可能导致这种行为差异?如何确保始终跟踪实体?

可以解决问题?

一些注释:

  • Wrapper类在这里显然毫无意义,但这是我的真实程序中更有意义的构造的最小示例,导致相同的行为。
  • 翻转foreach循环的顺序(使包装器的循环持续运行)会导致在两个循环中跟踪实体,因此在那种情况下,第一个环显然对第二个循环产生了副作用。
  • 将第一个foreach循环扩展到context.Thing.ToArray().Select(a => new Wrapper(a))(添加了ToArray)给出了预期的结果(跟踪实体),因此这似乎与迭代方法有关 - 但是如何?
  • 如何?

显然,EF代码解释Select(a => new Wrapper(a))Select(a => new { a.Id, a.Name } )相同。看不到包装器存储一个返回参考。

换句话说,它看到(认为)您正在立即转换实体,因此它决定不跟踪它。

在此处指定,但是您必须了解new{}部分也由EF处理。而您的new Wrapper(a)不是。

您可以尝试a => new Wrapper() {Thing = a},我对此不确定。

...第一个循环显然对第二个循环具有副作用。

是的,只要它们是相同连接的一部分。跟踪器不会"忘记"实体。您可以在这里阅读有关该内容的信息。

相关内容

  • 没有找到相关文章

最新更新