1215 / 806 / 244
Регистрация: 08.08.2014
Сообщений: 2,371
|
|||||||||||
1 | |||||||||||
EF: странности при повторном подключении04.08.2022, 14:38. Показов 2780. Ответов 22
Метки нет (Все метки)
Есть обычный EF-контекст (NET6).
Далее ситуация - SQL-сервер не доступен: Код
An error has occurred while establishing a connection to the server (code: 2) Далее, после обработки исключения, повторяется полностью аналогичный набор действий: 1. Создать новый экземпляр контекста (явным образом, т.е. тут нет никаких наводок от DI-контейнера) с той же строкой подключения. 2. Попытаться открыть подключение. Всё тоже ок, второй пункт корректно выдаёт такое же исключение. Однако, вторая попытка подключения выдаёт обозначенное выше исключение сразу же, т.е. вообще без таймаута. На всякий случай вывел в логи хэш самого контекста, хэш коннекта 'someContext.Database.GetDbConnection().GetHashCode()'. Разные, т.е. это точно полностью новый экземпляр и контекста, и самого коннекта к базе. Почему может быть такое поведение? Я предполагал, что каждый коннект будет отрабатывать независимо, и у каждого будет свой таймаут.
0
|
04.08.2022, 14:38 | |
Ответы с готовыми решениями:
22
USB устройство не определяется при повторном подключении При повторном подключении колонок - звука нет Пропадает звук при повторном подключении наушников Ошибка при повторном подключении к FTP и заливке При повторном подключении не работает блок питания от ноутбука |
3462 / 2473 / 695
Регистрация: 02.08.2011
Сообщений: 6,704
|
||||||
04.08.2022, 15:49 | 2 | |||||
Сообщение было отмечено kotelok как решение
Решение
Видимо, под капотом реализован circuit breaker. Чтобы не ждать подолгу каждый раз, когда захочется подключиться.
По-хорошему, надо смотреть исходники. Добавлено через 48 минут Для EFCore, в зависимости от СУБД разные провайдеры используются (ежу понятно). Для Sql Server есть сборка Microsoft.EntityFrameworkCore.SqlServer.dll, где есть тип SqlServerConnection (реализация IRelationalConnection), в котором есть реализация метода:
Поковыряться можно, конечно, если интересно. Добавлено через 5 минут По идее, разработчикам с опытом, это даже полезнее, чем чтение книжек по архитектуре, в какой-то степени.
1
|
12079 / 8388 / 1281
Регистрация: 21.01.2016
Сообщений: 31,601
|
|
10.08.2022, 12:52 | 3 |
0
|
1215 / 806 / 244
Регистрация: 08.08.2014
Сообщений: 2,371
|
|
10.08.2022, 19:07 [ТС] | 4 |
Для контролируемого открытия соединения и явного создания транзакции для него.
И чтобы потом это соединение можно было исползовать как в рамках EF-контекста, так и для прямых запросов к базе.
0
|
389 / 254 / 66
Регистрация: 12.04.2020
Сообщений: 1,329
|
|
10.08.2022, 21:51 | 5 |
0
|
10.08.2022, 22:21 | 6 |
Позанудстсвую с наводящими вопросами.
Это точно обычный контекст? Где работал с EF, мы только передаём строку подключения в конструктор контекста и забываем об этом навсегда. А вот для ADO.NET подходов это обычное дело - самим строку считать, коннект открыть, коннект проверить, закрыть, почистить... Вот "под капотом" у EF и лежит ADO. Или я ошибаюсь, или кто-то с EF работает как с ADO и получил неконтролируемое поведение, которое EF гарантирует (в общем в целом). Что есть GetHashCode? От чего он считался? Он может быть разный для разных экземпляров и разный для одних. Например, один коннект к БД имеет свой уникальный ИД. Почему бы какому-то клиенту не реализовать статический коннект для всех экземпляров? То о чём и сказал выше IamRain. А ещё есть такая штука - пул запросов. Тема тоже интересная. Вопрос - вы абсолютно точно понимаете что делаете? К тому что уверены что вам нужно именно контролировать открытые соединения и использовать как-то по особенному? Почему-то я всегда считал, начитавшить документации и описаний, что открыв контекст, открыв транзакцию, или передав транзакцию в соединение, я гарантирую что всё будет выполняться в рамках этой транзакции или соединения. До момента когда я явно скажу "всё... готово.. записывай.. закрывай..." У каждого действия должна быть причина. Если вы скажете что у вас запросы выполняются в хаотичных подключениях, вне транзакций... вот это да, проблема и стоит с этим и разбираться. А пока, это какие-то непонятные и пугающие действия. Из-за такого понимания жизненного цикла, в коде начинают встречаться трай-кэчи которые выполняют несколько повторных действий ("чтоб наверняка"), с последующим "гашением" в пустом catch. И на выходе метода "радостный успешный результат".
1
|
12079 / 8388 / 1281
Регистрация: 21.01.2016
Сообщений: 31,601
|
||||||
11.08.2022, 04:04 | 7 | |||||
Какой контроль? Зачем? ADO.NET умеет в ambient transactions (TransactionScope) без всякого ручного контроля со стороны разработчика.
То, что вы тут описали - лишнее. Сами проверьте:
На занимайтесь ерундой, всё до вас уже было реализовано.
1
|
11.08.2022, 08:50 | 8 |
Мои слова выше в эмоциональном стиле.
Я ещё добавлю. Какой контроль, kotelok, вам нужен? Хотите контроль - избавляйтесь от EF и работайте на кошерном ADO.NET. Люди писали, старались, сахарили, оборачивали чтобы не было явного контроля, а вы...
0
|
1215 / 806 / 244
Регистрация: 08.08.2014
Сообщений: 2,371
|
|
11.08.2022, 12:11 [ТС] | 9 |
Там и то, и то. Т.е. в рамках одной HTTP-сессии разные сервисы запрашивают один общий EF-контекст и далее могут использовать его:
1. Либо как EF-контекст. 2. Либо брать из него подключение к базе и работать с ним напрямую в рамках той же транзакции (через DbCommand или через Dapper). И во втором случае, полученное из EF-контекста подключение нужно открыть явным образом.
0
|
1215 / 806 / 244
Регистрация: 08.08.2014
Сообщений: 2,371
|
|
11.08.2022, 12:36 [ТС] | 12 |
Это тоже есть, но только для особых случаев и с последующей выдачей исключения (если не получилось).
Конкретная задача: 1. Пришёл HTTP-запрос. 2. Выполнился набор мидлваров до контроллера. 3. Далее контроллер должен вызвать сервис для обработки запроса. Сервис (через DI) может запросить другие сервисы. И все они должны работать в рамках одного подключения и одной транзакции, независимо от используемой библиотеки (EF, Dapper, ADO.NET). 4. Первый нюанс: подключения должны быть разными, в заивисимости от типа HTTP-запроса. Если GET-запрос, то используется аккаунт БД, имеющий права "только чтение" транзакция с уровнем изоляции 'read committed'. Если POST/PUT/DELETE/PATCH-запрос, то используется аккаунт БД с правами на запись и транзакция с изоляцией 'serializable'. 5. Второй нюанс: если вызов сервиса завершился с SQL-исключением 'transaction was deadlocked', то надо на уровне контроллера (ну или где-то между контроллером и сервисом) закрыть исходное подключение, создать новое и выполнить ещё одну попытку вызвать сервис. Если и со второй попытки не получилось, тогда уже вернуть ошибку. Все прочие ошибки обрабатываются штатным образом, т.е. после первой же попытки выдают в ответ либо HTTP-4XX, либо HTTP-500. Добавлено через 1 минуту Создать EF-контекст. НЕ выполнять через него никакие запросы. Взять из него подключение. Использовать это подключение для выполнения запроса ADO.NET (т.е. использовать, например, в SqlCommand).
0
|
12079 / 8388 / 1281
Регистрация: 21.01.2016
Сообщений: 31,601
|
|
11.08.2022, 12:44 | 13 |
Сообщение было отмечено kotelok как решение
Решение
Это вопрос
TransactionScope . Подключение одно шарить не нужно при этом! Их можно сколько угодно открывать и закрывать в рамках области видимости одной ambient транзакции.Описанные вами сложности происходят из незнания этого механизма)
1
|
1215 / 806 / 244
Регистрация: 08.08.2014
Сообщений: 2,371
|
||||||
13.09.2022, 12:47 [ТС] | 14 | |||||
Не подскажете, как правильно его использовать?
Попробовал вот так:
0
|
12079 / 8388 / 1281
Регистрация: 21.01.2016
Сообщений: 31,601
|
||||||
13.09.2022, 13:13 | 15 | |||||
Вы сделали дичь. На строке №18 вы открыли первое подключение, а в строке №21 открылось второе, в рамках одной транзакции. И получили распределённую транзакцию, а это или удар по производительности (в случае, если СУБД такое вообще поддерживает) или исключение, как в вашем случае.
Если собрались смешивать прямую работу с ADO и EF, то надо открывать и закрывать подключения в промежутках между обращениями к EF'у. Иначе получите, что получаете. Ну и транзакцию вы тоже неправильно создали. Зачем TransactionScopeAsyncFlowOption.Enabled , если в рамках транзакции нет асинхронщины? Зачем System.Transactions.IsolationLevel.Serializable , если это уровень изоляции по умолчанию?Добавлено через 1 минуту А это что за дичь?
IoC , как обёртка над строкой подключения...
1
|
1215 / 806 / 244
Регистрация: 08.08.2014
Сообщений: 2,371
|
|
13.09.2022, 13:17 [ТС] | 16 |
В реальном проекте есть асинхронные вызовы.
Затем, чтобы каждый раз не додумывать, что там по умолчанию. Как это вписать в DI? Запрашивать фабрику, затем у фабрики запрашивать IDbConnection и EF-контекст, потом не забывать их правильно закрывать. В т.ч. пред любыми вызовами вложенных сервисов, которые (вероятно) могут тоже работать с базой (а могут и не работать). Какая-то сомнительная полезность 'TransactionScope' получается под этот сценарий. Изначальный вариант с явным открытием подключения EF-контекста и с его последующим переиспользованием для ADO и Dapper выглядит намного менее проблемным для кода сервисов. Добавлено через 1 минуту Потому что это пример для форума. Пример, на котором повторяется. Без необходимости словами описывать окружение или копипастить кучу кусочков кода с регистрацией, запросом и настройкой контекста (для полноты картины).
0
|
12079 / 8388 / 1281
Регистрация: 21.01.2016
Сообщений: 31,601
|
||||||
13.09.2022, 13:22 | 17 | |||||
Тады ок)
Не надо ничего додумывать. По умолчанию там только одно значение - Serializable. Вы у DI запрашиваете экземпляр контекста и всё. И ничего не диспозите. Для этого у вас есть scope сервисов. Если у вас некий API, то этот скоуп уже определён жизнью контроллера. Если какое-то обычное десктопное приложение, то уже сами эти скоупы определяете. В том числе и во вложенных методах. Фразу про TransactionScope я не понял. Откуда вывод про сомнительную полезность?
0
|
1215 / 806 / 244
Регистрация: 08.08.2014
Сообщений: 2,371
|
||||||
13.09.2022, 13:34 [ТС] | 18 | |||||
Сценарий первый - сервису нужен и EF-контекст, и IDbConnection. Он их оба запрашивает и оба использует в какой-то последовательности. При этом внутри самого сервиса не хочется явно открывать/закрывать подключения и транзакции.
Сценарий второй:
0
|
1215 / 806 / 244
Регистрация: 08.08.2014
Сообщений: 2,371
|
|
14.09.2022, 08:51 [ТС] | 19 |
Я же уточнил - под этот сценарий. Т.е. когда в рамках одной транзакции с одной базой работает несколько сервисов разными способами и в разном порядке - один через EF, другой через IDbConnection(+ иногда Dapper), третий и то, и то использует.
0
|
12079 / 8388 / 1281
Регистрация: 21.01.2016
Сообщений: 31,601
|
|
14.09.2022, 16:31 | 20 |
Открывать\закрывать подключение придётся. Более того: это будет даже весьма просто. Ведь вся работа с базой будет изолирована в другом сервисе - репозитории. А он будет управлять подключением. Это правильный подход.
Тут я проблемы не вижу. Каждый метод второго сервиса открывает подключение явно, а потом его закрывает. Никаких пересечений с EF. Одна транзакция на оба способа работы с СУБД. Так, а сомнительность TransactionScope откуда берётся? Основное требование - не держать подключение к базе постоянно открытым и всё. Выполняется оно очень легко и просто.
1
|
14.09.2022, 16:31 | |
14.09.2022, 16:31 | |
Помогаю со студенческими работами здесь
20
Раздача вайфая в windows server (при повторном подключении не удается соединиться) Перестает "работать" сервер при повторном подключении клиента Странности в подключении Странности в сетевом подключении Сделать так чтобы при подключении нулевого порта выполнялся один цикл кода а при подключении другого - другой При первом нажатии кнопки - выполнялся один код,при повторном другой и тд Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |