Я использую Entity Framework Core для извлечения сущностей, уже хранящихся в базе данных, но в зависимости от того, как я это делаю, они иногда извлекаются в состоянии «Отдельно», даже когда я вообще не использую 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
Inдругими словами, сущности отсоединяются, если извлекаются, а затем передаются в конструктор Wrapper
, но отслеживаются (в состоянии «Неизменен»), если просто регулярно извлекаются.
Насколько я понимаю, сущности уже сохранены в базе данныхвсегда следует извлекать в отслеживаемом состоянии, если только явно не получено с AsNoTracking
, так что может вызвать эту разницу в поведении?И как это можно исправить, чтобы убедиться, что сущности всегда отслеживаются?
Несколько замечаний:
- Класс
Wrapper
здесь явно бессмыслен, но это минимальный примерболее значимая конструкция в моей реальной программе, которая вызывает такое же поведение. - Изменение порядка циклов
foreach
(так, чтобы цикл с оберткой выполнялся последним) заставляет отслеживать объекты в обоих циклах,поэтому в этом случае первый цикл явно оказывает побочный эффект на второй цикл. - Расширение первого цикла
foreach
для итерации по context.Thing.ToArray().Select(a => new Wrapper(a))
(с добавлением ToArray
) дает ожидаемый результат (отслеживаетсясущности), так что это, похоже, связано с методом итерации - но как?