Как лучше хранить GUID в базе (тип данных)?
Данные выдаются как IAsyncEnumerable. Одна компонента начинает асинк запрос на чтение базы, потом, по идее идет дальше, переходит в другую и опять начинает асинк запрос на чтение. Вот этот второй запрос и выдает исключение, что мол, типа нефиг вызывать один контекст их двух разных потоков. Но что то непонятно, откуда несколько потоков при отрисовки компоненты, по идее всё в одном ui потоке должно быть. Да и с ораклом то всё работало и работает, с тем же кодом....Осталось еще проверить номера потоков, что бы наверняка знать
Гм. Это какой-то шарпный/EF геморрой. Тут я не помогу. Так-то у постгреса нет никаких проблем с паралелльным доступом. Ну, если кто-то с какого-то перепугу не выставил isolation level в serializable конечно.
P.S. Ну и если мелокомягкие не изобрели какое-то очередное гавно вроде замыканий по ссылке, то конечно же вызванные черезе await-async методы могут выполнятся в разных потоках. Какой-то пул потоков должен быть.
Лечится либо задержкой между вызовами, либо переделкой на синхронное чтение из базы. Но ни то ни другое, как то не хочется.
Попробуйте ещё виртуализацию на клиенте сделать, чтобы запрашивалась только та часть, что сейчас отображается (с запасом в начале и конце списков). Тогда запросы будут быстрые и данных будет передаваться немного. Может, они и не пересекутся. Обычно в популярных Blazor-фреймворках такая виртуализация из коробки есть.
Зачем тут вообще IAsyncEnumerable не понял. Первый раз эту штуку встречаю. Если запросы маленькие, может, можно и без этого обойтись?
Тестовый проект очень простой:
Главная компонента, вызывает вложенную компоненту, та еще одну. Код 1й вложенной компоненты, остальное тоже самое практически
Child 1 Component enter await thread @idOfRenderingThreadIn continue thread @idOfRenderingThreadOut <Child2Component></Child2Component> @code { private int idOfRenderingThreadIn; private int idOfRenderingThreadOut; protected override async Task OnInitializedAsync() { idOfRenderingThreadIn = System.Threading.Thread.CurrentThread.ManagedThreadId; await base.OnInitializedAsync(); await Task.Delay(10); idOfRenderingThreadOut = System.Threading.Thread.CurrentThread.ManagedThreadId; } }
Результат выполнения
и нашлось: что только для Blazor server повторный вход в компоненту может быть из другого потока (точнее речь идет об отрисовке)
Ошибка:
error: 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 https://go.microsoft.com/fwlink/?linkid=2097913.
По ссылке ничего полезного не нашлось для данного случая.
То бишь отчего не работает, стало вроде понятно. А вот отчего Оракл работает еще непонятно.
Попробуйте ещё виртуализацию на клиенте сделать
не поможет, и не нужно. Относительно мало данных
Если запросы маленькие, может, можно и без этого обойтись?
отрисовка все замедляется, а при первом запросе в день будет совсем плохо.
IAsyncEnumerable
Тоже не любитель но иногда полезно
лечится только созданием/уничтожением контекста прямо в запросе.
public class FooByIdDataLoader { private readonly IDbContextFactory _dbContextFactory; public FooByIdDataLoader(IDbContextFactory dbContextFactory) { _dbContextFactory = dbContextFactory; } protected override async Task> LoadBatchAsync(IReadOnlyList keys, CancellationToken ct) { await using ApplicationDbContext dbContext = _dbContextFactory.CreateDbContext(); return await dbContext.Foos .Where(s => keys.Contains(s.Id)) .ToDictionaryAsync(t => t.Id, ct); } }
Хорошо что ты сказал, хотел показать другое, что раньше видел, а тут новое.
Слева сидим в exception, а справа фигня, что драйвер еще "секретно" делает видимо, тогда это объясняет отчего с ораклом работает.
Если бы еще понять что это должно значить...
Черт, забыл что картинку только из файла можно вставить, исправил. Слева там, где exception при чтении с базы, справа, что в "паралельном" стеке.
срабатывает регулярно
Увы, радость была напрасной. Всё исключительно что приведено исключительно в тестовом приложении сейчас получается, на деле как и раньше было, два async запроса по чтению.
И никакие исправления не получаются. Кто то додумался использовать аж 4 глобальных параметра, каждый из которых грузится из базы.
https://learn.microsoft.com/en-us/aspnet/core/blazor/compo...
И любые изменения приводят к тому, что один из них, по крайней мере, становится нулем. Контексты как я выше, в примере сделал, тоже пока не получается разделить, там иерархия контекстов.
Похоже мелкими изменениями не обойтись