Я использую реализацию области видимости DbContext. В основном это означает, что я использую подход DbContext. Дополнительная информация
Я упростил свой реальный код и удалил всю логику, связанную с поведением потока контекста ...
using (var dbContextParentScope = ...)
{
DbContext parentContext = dbContextParentScope.Get<ApplicationContext>();
// that data will be in the DbContext cache
var accounts = parentContext.Accounts.ToList();
// this is always part of a separate method
using (var dbContextChildScope = ...)
{
DbContext childContext = dbContextChildScope.Get<ApplicationContext>();
var childAccounts = childContext.Accounts.ToList();
childAccounts.ForEach(a => a.DisplayName = "New name");
// after that operation parentContext data will be outdated
childContext.SaveChanges();
// this will reload updated entities in the parentContext
dbContextChildScope.RefreshEntitiesInParentScope(childAccounts);
}
// without Refresh operation we will work with outdated data
parentContext.SaveChanges();
}
Это исключительный случай, но иногда нам приходится сохранять важную информацию вне основной транзакции.
Entity Framework имеет возможность получить запись по ключу от DbContext:
if (((IObjectContextAdapter)childContext).ObjectContext.ObjectStateManager.TryGetObjectStateEntry(childAccounts[0], out ObjectStateEntry stateInChildScope))
{
var key = stateInChildScope.EntityKey;
if (((IObjectContextAdapter)parentContext).ObjectContext.ObjectStateManager.TryGetObjectStateEntry(key, out ObjectStateEntry stateInParentScope))
{
if (stateInParentScope.State == EntityState.Unchanged)
{
((IObjectContextAdapter)parentContext).ObjectContext.Refresh(RefreshMode.StoreWins, stateInParentScope.Entity);
}
}
}
EF Core не имеет такой функциональности, но имеет «ChangeTracker». Может возвращать записи, которые отслеживает DbContext:
parentContext.ChangeTracker.Entries().Where(w => w.State == EntityState.Unchanged).ToList()
Но я хочу перезагрузить только те записи, которые были обновлены в childContext. Так что, если я напишу что-то вроде этого:
var updatedEntry = childContext.Entry(childAccounts[0]);
parentContext.Entry(updatedEntry.Entity).Reload();
EF Core думает о updatedEntry как о новом и выдает System.InvalidOperationException:
Экземпляр типа сущности "Account" не может быть отслежен, поскольку другой экземпляр с тем же значением ключа для {'EntityId'} уже отслеживается. При подключении существующих объектов убедитесь, что подключен только один экземпляр объекта с данным значением ключа.
Также я обнаружил некоторые внутренние функции, но я не хочу использовать внутренний код EF Core (за исключением того, что это единственный способ заставить его работать), потому что его можно изменить / удалить:
var entityType = parentContext.Model.FindEntityType(typeof(TEntityType));
var key = entityType.FindPrimaryKey();
var stateManager = parentContext.GetDependencies().StateManager;
var keysDictionary = key.Properties.ToDictionary(x => x.Name, x => x.PropertyInfo.GetValue(childAccounts[0]));
var entry = stateManager.TryGetEntry(key, keysDictionary.Values.ToArray());
parentContext.Entry(entry.Entity).Reload();
Кто-нибудь знает, как я могу обновить сущности из родительского контекста?
Я надеюсь на вашу помощь, потому что я застрял здесь и у меня закончились какие-либо идеи