简体   繁体   English

什么可以导致DbSet中的持久化实体被分离?

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

I'm using Entity Framework Core to retrieve entities already stored in the database, but depending on how I do that, they are sometimes retrieved in the "Detached" state, even when I'm not using AsNoTracking at all. 我正在使用Entity Framework Core来检索已经存储在数据库中的实体,但是根据我的方式,它们有时会在“Detached”状态下被检索,即使我根本不使用AsNoTracking

These are the classes used to model the database: 这些是用于建模数据库的类:

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

The following is a class used to reproduce the scenario where the entities are retrieved in a detached state: 以下是用于重现以分离状态检索实体的方案的类:

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

The main program then does the following: 主程序然后执行以下操作:

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

Assuming there are three rows in the Thing table, the output becomes the following: 假设Thing表中有三行,则输出如下:

Detached
Detached
Detached
Unchanged
Unchanged
Unchanged

In other words, the entities are detached if retrieved and then passed into the Wrapper constructor but tracked (in the "Unchanged" state) if simply retrieved regularly. 换句话说,如果检索实体,则将其分离,然后传递到Wrapper构造函数,但如果只是定期检索,则会跟踪(处于“未更改”状态)。

It is my understanding that entities already persisted to the database should always be retrieved in a tracked state unless explicitly retrieved with AsNoTracking , so what could cause this difference in behavior? 我的理解是,除非使用AsNoTracking显式检索,否则应始终在跟踪状态下检索已AsNoTracking到数据库的实体,那么可能导致这种行为差异的原因是什么? And how could it be fixed to make sure the entities are always tracked? 如何修复以确保始终跟踪实体?

A few notes: 几点说明:

  • The Wrapper class is clearly pointless here, but it's a minimal example of a more meaningful construct in my real program that causes the same behavior. Wrapper类在这里显然毫无意义,但它是我真实程序中一个更有意义的构造的最小例子,它导致相同的行为。
  • Flipping the order of the foreach loops (so that the one with the wrapper runs last) causes the entities to be tracked in both loops, so in that case the first loop clearly has a side effect on the second loop. 翻转foreach循环的顺序(以使包装器最后运行的循环)导致在两个循环中跟踪实体,因此在这种情况下,第一个循环明显对第二个循环产生副作用。
  • Extending the first foreach loop to iterate over context.Thing.ToArray().Select(a => new Wrapper(a)) (with a ToArray added) gives the expected result (tracked entities), so this seems to be related to the method of iteration - but how? 扩展第一个foreach循环以迭代context.Thing.ToArray().Select(a => new Wrapper(a)) (添加了ToArray )给出预期结果(跟踪实体),所以这似乎与迭代的方法 - 但如何?

Apparently, the EF code interprets Select(a => new Wrapper(a)) the same as Select(a => new { a.Id, a.Name } ) . 显然,EF代码解释Select(a => new Wrapper(a))Select(a => new { a.Id, a.Name } )相同Select(a => new { a.Id, a.Name } ) It cannot see that a Wrapper stores a back reference. 它看不到Wrapper存储后引用。

In other words, it sees (thinks) you are immediately converting the entity so it decides not to track it. 换句话说,它看到(认为)您正在立即转换实体,因此它决定不跟踪它。

It is specified here , but you have to understand that the new{} part is also processed by EF. 在此处指定,但您必须了解new{}部分也由EF处理。 And your new Wrapper(a) is not. 你的new Wrapper(a)不是。

You could try a => new Wrapper() {Thing = a} , I'm not 100% sure about that. 你可以试试a => new Wrapper() {Thing = a} ,我对此并不是100%肯定。

... the first loop clearly has a side effect on the second loop. ......第一个循环显然对第二个循环有副作用。

Yes, as long as they are part of the same connection. 是的,只要它们是同一连接的一部分。 The tracker won't 'forget' entities. 跟踪器不会“忘记”实体。 You can read about that here . 你可以在这里阅读。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM