Обновить конкретную запись сущности в контексте EF Core - PullRequest
1 голос
/ 25 марта 2019

Я использую реализацию области видимости 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();

Кто-нибудь знает, как я могу обновить сущности из родительского контекста?

Я надеюсь на вашу помощь, потому что я застрял здесь и у меня закончились какие-либо идеи

...