AsNoTracking () не возвращает несохраненные изменения - PullRequest
0 голосов
/ 20 июня 2020

В документации для AsNoTracking () в Entity Framework Core говорится, что любые изменения в нем не будут сохраняться при сохранении контекста базы данных. Я заметил еще одно отличие при использовании AsNoTracking (), а именно: если в контексте базы данных есть несохраненные изменения и вы запрашиваете его с помощью AsNoTracking (), эти изменения не будут возвращены. В документации создается впечатление, что только изменения, внесенные в запрос AsNoTracking (), не будут отслеживаться и сохраняться при сохранении, но кажется, что возвращаемое содержимое также будет другим.

Если это действительно предполагаемое поведение , Я не уверен в лучшем шаблоне проектирования. Я использовал AsNoTracking () во всех моих запросах только для чтения, но это означает, что у меня есть ошибка, поскольку мой дизайн выглядит примерно так:

Конечная точка контроллера, которая изменяет данные:

  1. Вызвать что-то в службе, которая может или не может изменить db
  2. Вызвать что-нибудь еще в службе, которая выполняет запрос только для чтения с AsNoTracking ()
  3. Контроллер сохраняет контекст базы данных

Предполагается, что любая конечная точка контроллера может вызывать любое количество сервисных методов, которые могут или не могут изменять базу данных, контексты базы данных ограничены, поэтому они разделяются между вызовами, и в конечном итоге контроллер сохраняет изменения . Проблема в том, что №2 из приведенного выше не вернет изменений, сделанных в №1. Как это решить? Службы могут вызывать другие службы, которые могут получать некоторые данные из мест, которые уже были изменены, поэтому я не могу просто передавать модели повсюду. Должен ли я просто удалить AsNoTracking () отовсюду и покончить с этим? Или мне следует добавлять вызов сохранения после каждой записи? Или есть еще что-нибудь, что я могу сделать?

TL; DR: я хочу, чтобы AsNoTracking () использовался в запросах только для чтения для повышения скорости, но он не вернет никаких несохраненных изменений. Следует ли мне удалять AsNoTracking (), сохранять после каждого редактирования или есть лучший способ?

Изменить: вот отрывок того, что я имею в виду; любой запрос с AsNoTracking () игнорирует любые изменения, внесенные в контекст до его сохранения, что заставляет меня задаться вопросом, как AsNoTracking () может быть вообще тогда полезен:

var userSessionEntry = await this.mainContext.Sessions
    .Where(t => t.AccountId == session.AccountId).FirstAsync();

userSessionEntry.AccountId = Guid.Empty;

var userSessionEntry2 = await this.mainContext.Sessions
    .Where(t => t.AccountId == session.AccountId).AsNoTracking().FirstAsync();

Console.WriteLine(userSessionEntry2.AccountId); // prints original AccountId and not an empty id

Редактировать 2: Я использую последнюю версию предварительная версия Entity Framework Core; 5.0.0-preview.5.20278.

Спасибо.

1 Ответ

0 голосов
/ 21 июня 2020

Принцип работы AsNoTracking заключается в том, что он всегда будет обходить объекты собственного кэша (отслеживаемые изменениями) DbContext и напрямую выполнять запрос к базе данных. Вот что подразумевается под определением. Кэшированные данные могут отличаться от данных базовой базы данных, если кто-то другой вносит изменения в те же сущности, с которыми вы работаете.

Однако, согласно вашему проекту, если все службы в вашем контроллере используют одни и те же точные DbContext Например, тогда у вас все будет хорошо. Есть способы сделать это, используя внедрение зависимостей контекста вашей базы данных в любые ваши сервисы. Таким образом, все части вашего запроса на обслуживание должны использовать один и тот же экземпляр.

Если вам постоянно нужны самые свежие данные, тогда вам нужно будет использовать AsNoTracking для всех запросов, которые вы делаете. поэтому вы всегда попадаете в базу данных для получения самых свежих данных.

Вы по-прежнему можете вносить изменения в объекты, изменения которых больше не отслеживаются, но потребуется дополнительный код:

var managers = await DbContext.Set<Employee>()
    .AsNoTracking()
    .Where(x => x.IsManager)
    .ToListAsync();

foreach (var manager in managers)
{
    manager.Salary += 10000;

    var dbEntry = DbContext.DbEntry(manager);
    dbEntry.Property(x => x.Salary).IsModified = true;
}

await DbContext.SaveChangesAsync();

Вы Вы можете использовать описанную выше стратегию, чтобы всегда работать с самыми свежими данными. Если у вас есть тысячи пользователей, активно использующих ваш сервис, это может действительно сильно ударить по вашей базе данных, поэтому вам подойдет некоторая стратегия кэширования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...