EF Core изменяет отслеживаемые объекты, устанавливая ключи и сохраняя свойства навигации.
В качестве примера того, почему это может быть проблемой, предположим, что вы запускаете задачу, которая добавит сущность в DbContext. Если вы затем немедленно пронумеруете некоторые навигационные свойства того же объекта, не дожидаясь завершения задачи, вы можете получить InvalidOperationException
. Когда объект отслеживался в другом потоке, он мог получить некоторые другие данные из контекста и изменить коллекцию.
Я хотел бы избежать этих проблем, клонируя объекты, входящие и исходящие из EF Core. Но я также не хочу писать тонну неподдерживаемого и подверженного ошибкам кода для клонирования сущностей вручную.
Вот как далеко я продвинулся:
public static TEntity CloneEntity<TEntity>(this DbContext context, TEntity entity)
where TEntity : class
{
if (context == null)
throw new ArgumentNullException(nameof(context));
if (entity == null)
throw new ArgumentNullException(nameof(entity));
// A map for keeping track of already-cloned objects for circular references.
var map = new Dictionary<object, object>(ReferenceEqualityComparer.Instance);
return (TEntity)Recurse(context.Entry(entity));
object Recurse(EntityEntry entry)
{
if (map.TryGetValue(entry.Entity, out var clone))
return clone;
clone = entry.CurrentValues.ToObject();
map.Add(entry.Entity, clone);
// TODO: Recursively clone and set all the navigation properties.
return clone;
}
}
Я, вероятно, могу понять, как решить бит TODO с помощью отражения, но EF Core уже должен был сделать все это, и у него уже должны были быть скомпилированные методы для эффективной настройки свойств навигации. Есть ли способ использовать их, похожие на entry.CurrentValues.ToObject()
?