什么会导致 DbSet 中的持久化实体分离?

What can cause persisted entities from a DbSet to be detached?

我正在使用 Entity Framework Core 检索已存储在数据库中的实体,但根据我的操作方式,它们有时会以 "Detached" 状态检索,即使我正在根本不使用 AsNoTracking

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

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用于重现在分离状态下检索实体的场景:

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);
}

假设Thingtable中有三行,输出变成如下:

Detached
Detached
Detached
Unchanged
Unchanged
Unchanged

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

据我了解,除非使用 AsNoTracking 显式检索,否则应始终以跟踪状态检索已经保存到数据库中的实体,那么是什么导致了这种行为差异?以及如何修复以确保始终跟踪实体?

一些注意事项:

显然,EF 代码解释 Select(a => new Wrapper(a))Select(a => new { a.Id, a.Name } ) 相同。它看不到 Wrapper 存储反向引用。

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

指定了here,但是你要明白new{}部分也是EF处理的。而你的 new Wrapper(a) 不是。

你可以试试 a => new Wrapper() {Thing = a},我不是 100% 确定。

... the first loop clearly has a side effect on the second loop.

可以,只要它们属于同一连接即可。跟踪器不会 'forget' 个实体。您可以阅读有关 here 的内容。