Как стать автором
Обновить

Комментарии 10

Особенности EF не зависят от того используется он в Blazer или в обычном консольном приложении.

Это верно, но эта статья создана для тех, кто видит такое исключение впервые и именно на Blazor, так как например при создании API-сервера такие ошибки почти не возникают.

Здесь важно время существования контекста, создаваемого контейнером DI.

По этому критерию можно разделить на две группы:

  • консольки, MVC, web-api: один экземпляр на запрос, Singleton / Transient работают как ожидается;

  • blazor server, win form, win service: один экземпляр на приложение, Singleton/Transient эквивалентны.

Вы рассматриваете только вариант несколько контекстов на одной странице.

Гораздо чаще (и болезнее) вариант многопользовательской работы.

Поэтому использование фабрики в случае blazor server – практически безальтернативно.

 

Но при чем здесь конкретно blazor server? Напороться на такую проблему приходилось, я думаю, каждому, кто хоть когда использовал EF, хоть с blazor, хоть без него.

А по сути проблемы - ну да, а что вы хотели, если есть два контекста, которые работают с одними и теми же сущностями, вы получите конфликт.

Решение, в принципе, очевидно: не трекать сущности на чтение, держать один контекст и трекать всё него при выполнении обозначенной бизнес-операции.

И кстати, а почему вы не упомянули .AsNoTracking()?

Решение с одним контекстом не всегда можно использовать. Особенно если у вас большой проект и вам нужно разделить страницу на множество компонентов, для которых нужны свои данные из БД. Вытягивать все данные в родительском компоненте и после передавать их в качестве параметра - не всегда удобно. Например, если у вас вложенная структура и нужно передать данные 4-му дочернему компоненту. По поводу .AsNoTracking() - он выполняет тот же функционал, что и удаление контекста.

Попробуйте каскадный параметр.

Он специально для простого доступа из глубины дерева компонентов предназначен.

я правильно понял проблему?

что есть список айдишников userIds = [1,2,3]

делается рендер "карточек" передавая в параметре только userID

{loop}

<UserCard :userID ="i" >

{/loop}

А во время рендера этих карточек получается идет запрос в DB ?

onRender( db.getUserByID(i) )

И получается что если рендерить сразу 50 пользователей то это 50 запросов к бд вместо одного ?

Проблема именно в том, что все эти 50 запросов будут выполнены одновременно, из разных потоков и в одном контексте. А так как DbContext не является thread-safe, то есть не позволяет двум потокам одновременно с ним работать, возникает первая ошибка.

Создавать на каждый метод или компонент, который может выполняться асинхронно, новый DbContext. Такой функционал можно реализовать через DbContextFactory или IServiceScopeFactory.

а зачем?
или у вас все классы бизнес логики синглтоны?

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

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории