Форум программистов, компьютерный форум, киберфорум
C#: Базы данных
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/3: Рейтинг темы: голосов - 3, средняя оценка - 4.67
1 / 1 / 1
Регистрация: 07.03.2018
Сообщений: 91
.NET 9

A second operation was started on this context instance before a previous operation completed

22.01.2025, 11:41. Показов 1820. Ответов 7

Студворк — интернет-сервис помощи студентам
Написал VM общего перечня. Если вызвать метод SearchMyClass во второй раз, до завершения первого вызова, то (MyClassRepository, 7) выдаёт:
System.InvalidOperationException: A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see [url]https://go.microsoft.com/fwlink/?linkid=2097913[/url].
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public class MyViewModel : BindableBase
{
    private readonly MyClassRepository _myClassRepository;
    private CancellationTokenSource _cancellationTokenSource; 
    private readonly DispatcherTimer _debounceTimer;
 
    private string _number;
    public string Number
    {
        get => _number;
        set
        {
            SetProperty(ref _number, value); 
            _debounceTimer.Stop();
            _debounceTimer.Start();
        }
    }
 
    private ObservableCollection<MyClass> _myClassList;
    public ObservableCollection<MyClass> MyClassList
    {
        get => _myClassList;
        set => SetProperty(ref _myClassList, value);
    }
 
    public MyViewModel(MyClassRepository myClassRepository)
    {
        _myClassRepository = myClassRepository;
 
        MyClassList = [];
 
        _debounceTimer = new DispatcherTimer
        {
            Interval = TimeSpan.FromMilliseconds(500)
        };
        _debounceTimer.Tick += async (_, _) =>
        {
            _debounceTimer.Stop();
            await SearchMyClass();
        };
    }
 
    private async Task SearchMyClass()
    {
        _cancellationTokenSource?.Cancel();
 
        if (string.IsNullOrWhiteSpace(Number))
        {
            MyClassList.Clear();
            return;
        }
 
        _cancellationTokenSource = new();
 
        try
        {
            var result = await _myClassRepository.GetByNumberAsync(Number, _cancellationTokenSource.Token);
 
            MyClassList = new(result);
        }
        catch (OperationCanceledException) { }
    }
}
C#
1
2
3
4
5
6
7
8
9
public class MyClassRepository(MyDbContext context)
{
    public async Task<IEnumerable<MyClass>> GetByNumberAsync (string number, CancellationToken cancellationToken = default)
    {
        var query = context.Set<MyClass>().AsQueryable();
        ...
        return await query.ToListAsync(cancellationToken);
    }
}
Ставил точку отладки на catch - туда не заходит. MyDbContext зарегистрирован как transient. Что я делаю не так?
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
22.01.2025, 11:41
Ответы с готовыми решениями:

Entity Framework Core: A second operation was started on this context instance before a previous operation
Всем привет, есть игровой сервер на C#, на каждого клиента создается задача, решил использовать единый контекст Entity Framework Core для...

Ошибка The Undo operation encountered a context that is different from what was applied in the corresponding Set operation...
The Undo operation encountered a context that is different from what was applied in the corresponding Set operation.The possible cause...

The operation cannot be completed. See the details. Eclipse
Здравствуйте, я работаю в Eclipse Не могу установить плагин, выдаёт ошибку The operation cannot be completed. See the details. ...

7
Эксперт .NET
 Аватар для Wolfdp
3789 / 1766 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
22.01.2025, 11:59
Цитата Сообщение от Stormhead Посмотреть сообщение
Что я делаю не так?
нужно дождаться отмены. Введите AutoResetEvent (или как его там) и обязательно работайте с ним тоже асинхронно, т.к. вызов вашего SearchMyClass я так понимаю из UI потока, а завершение второй операции по идеи будет дожидаться этого самого UI.

Ещё я бы в catch (OperationCanceledException) чекал что _cancellationTokenSource is canceled (а то мало ли что там упало с таким исключением) и таки делал Dispose для него.
1
1339 / 919 / 264
Регистрация: 08.08.2014
Сообщений: 2,763
22.01.2025, 20:18
Лучший ответ Сообщение было отмечено Stormhead как решение

Решение

Цитата Сообщение от Stormhead Посмотреть сообщение
MyDbContext зарегистрирован как transient
Так вы его всё равно один раз в конструктор запрашиваете (MyViewModel -> MyClassRepository -> MyDbContext), сохраняете в поле класса и потом переиспользуете.

Всё же, более типовое использование EF-контекста (ну или репозитория):
C#
1
2
3
4
5
6
7
8
9
10
11
12
public class MyClassRepository(MyDbContextFactory contextFactory)
{
    public async Task<IEnumerable<MyClass>> GetByNumberAsync (string number, CancellationToken cancellationToken = default)
    {
        using (var context = contextFactory.Create())
        {
            var query = context.Set<MyClass>().AsQueryable();
            ...
            return await query.ToListAsync(cancellationToken);
        }
    }
}
Цитата Сообщение от Stormhead Посмотреть сообщение
Ставил точку отладки на catch - туда не заходит
У вас catch отлавливает только 'OperationCanceledException', а прилетает 'InvalidOperationException'.
1
1 / 1 / 1
Регистрация: 07.03.2018
Сообщений: 91
23.01.2025, 10:05  [ТС]
Цитата Сообщение от kotelok Посмотреть сообщение
Всё же, более типовое использование EF-контекста (ну или репозитория):
Не встречал подобного решения. Оно как раз отвечает на один из моих вопросов «Как всегда получать актуальные данные?». Но в таком случае быстродействие не сильно снизится?
Если я правильно понимаю, то в моём случае все ранее найденные номера кэшируются в контексте и при повторном поиске результат возвращается быстрее. Да ещё и контекст каждый раз создавать.
0
1339 / 919 / 264
Регистрация: 08.08.2014
Сообщений: 2,763
23.01.2025, 10:50
Цитата Сообщение от Stormhead Посмотреть сообщение
в таком случае быстродействие не сильно снизится?
Наоборот, скорее.

Модель EF-контекст строит один раз, при первом использовании, потому первое создание контекста всегда на порядки медленнее последующих.

Подключения к БД берутся из пула (ну, они оттуда берутся даже когда через один и тот же экземпляр EF-контекста несколько отдельных запросов выполняется, ну т.е. EF внутри себя не держит постоянно открытое подключение к БД).

А вот сам контекст, и его кэш для для отслеживания изменений, замусоривается и разрастается.

Цитата Сообщение от Stormhead Посмотреть сообщение
в моём случае все ранее найденные номера кэшируются в контексте
У вас в коде этого не видно, ну т.е. у вас каждй раз выполняется:
C#
1
2
3
            var query = context.Set<MyClass>().AsQueryable();
            ...
            return await query.ToListAsync(cancellationToken);
Ну т.е. EF каждый раз строит SQL-запрос согласно требованиям, сформированным в 'query', подключается к БД, выполняе запрос и получает данные.
1
1 / 1 / 1
Регистрация: 07.03.2018
Сообщений: 91
13.02.2025, 11:18  [ТС]
Так, окей. На Get* методах репозиториев работает хорошо. Теперь мне нужно сделать Update (SaveChanges в VM редактирования MyClass). Unit of Work?

Тогда вернуть в конструктор репозиториев непосредственно сам контекст, а фабрику получать UoW’ом и при обращении к репозиторию в UoW… инициализировать его контекстом из фабрики? Бессмыслица получается, зачем тогда сам UoW. В конструкторе же бессмысленно будет создавать и запоминать контекст? В таком случае вернётся проблема из заголовка.

Да ещё и на каждую сущность прописывать свойство репозитория в UoW…

В общем, kotelok, прошу вашей помощи.
0
1339 / 919 / 264
Регистрация: 08.08.2014
Сообщений: 2,763
13.02.2025, 11:56
Не очень понятна суть проблемы - получаем айтем из БД в режиме отслеживания изменений, меняем свойства, сохраняем.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public sealed class SomeRepository(ContextFactory _contextFactory)
{
    public void UpdateSome(SomeDto someDto)
    {
        using var context = _contextFactory.CreateContext();
        
        var someEntity = context.Some.AsTracking().FirstOrDefault(s => s.SomeId == someDto.Id)
            ?? throw new ItemNotFoundException(...);
 
        someEntity.Data = someDto.Data;
 
        context.SaveChanges();
    }
}
Если в рамках какого-то бизнес-процесса требуется согласованное изменение несколько сущностей через разные репозитории, то в том коде, который находится выше репозиториев, можно использовать TransactionScope.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public sealed class OtherModel(ISomeRepository _someRepository, INextRepository _nextRepository)
{
    public void ProcData(OtherDto otherDto)
    {
        using (var scope = new TransactionScope(...))
        {
            //Какие-то данные из репозиториев.
            var some = _someRepository.GetSome(...);
            var someStatus = _someRepository.GetSomeStatus(...);
            var next = _nextRepository.GetNext(...);
 
            //Какая-то бизнес-логика на базе 'some', 'next' и 'ohterDto'.
            //..
 
            //Какие-то изменения
            _someRepository.UpdateSome(...);
            _nextRepository.Remove(...);
            _nextRepository.Update(...);
 
            scope.Complete();
        }
    }
}
C#
1
2
3
4
5
6
7
public sealed class SampleViewModel(OtherModel _otherModel)
{
    public void SomeCommand()
    {
        _otherModel.ProcData(...);
    }
}
1
Эксперт .NET
 Аватар для Usaga
14096 / 9313 / 1349
Регистрация: 21.01.2016
Сообщений: 34,988
13.02.2025, 16:46
Цитата Сообщение от kotelok Посмотреть сообщение
Если в рамках какого-то бизнес-процесса требуется согласованное изменение несколько сущностей через разные репозитории
Да и в рамках одного репозитория такое согласование тоже нужно может быть, как в том же UpdateSome выше.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
13.02.2025, 16:46
Помогаю со студенческими работами здесь

Невозможно расшарить принтер (Printer settings could not be saved. Operation could not be completed (error 0x00000001)
Такая проблема, может кто знает решение, я лично не смог нагуглить. Есть Windows 7 x64 и принтер подключенный по USB (неважно какой, ну...

Ошибка при открытии добавленного в проект docx файла. The operation could not be completed. Параметр задан неверно
Всем привет. Возникает ошибка при открытии добавленного в проект docx-файла. Т.е. ожидается, что он должен открыться в Word. ...

Entity Framework. Context instance has been disposed
Всем привет. Ошибка такова - The ObjectContext instance has been disposed and can no longer be used for operations that require a...

Operation not permitted
Здравствуйте, скажите как можно &quot;обойти&quot; запрет на использование некоторых функций, к примеру opendir(&quot;/proc&quot;) или getpwuid()? ...

Operation may be undefined
std::shared_ptr&lt;unsigned char&gt; hmacSha1(getHMACSha1(counter, std::to_string(1))); uint32_t...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Новые блоги и статьи
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Ниже машинный перевод статьи The Thinkpad X220 Tablet is the best budget school laptop period . Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы,. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru