До недавнего времени я, для работы с БД, использовал dapper. Он мне всем нравится, но, по современным меркам, уж больно он "низкоуровневый".
Использовал ef core, который работал стабильно, то слабоват, когда много однотипных таблиц вида object_####_, они часто меняются и меняется структура.
Требуются постоянные запросы с разным составом полей. И что понадобится в следующий раз пользователям, неизвестно.
Мне, несколькими тредами ниже, посоветовали LinqToDb, мол он всё это умеет. И да, он умел практически всё что надо.
Сделал я тестовое приложение. Идёт чтение, в n-тасков, большой таблицы из постгреса. После чтения записи, надо получить запись с сервера mysql, и обновить полученную запись в постгреса.
Таски запускаются через Task.Factory.StartNew(...)
Постгрес справляется на ура, всё хорошо. А, вот с MySql возникла проблема.
В таске выполняется так:
LinqToDbConnectionOptionsBuilder myBuilder = new LinqToDbConnectionOptionsBuilder();
myBuilder.UseMySql("тут ConnectionString");
await using DataConnection myDataConnection = new DataConnection(myBuilder.Build());
foreach (LayerTable item in page)
{
DataParameter f = new DataParameter("@id", item.RowId, DataType.Int32);
List<IDictionary<string, object>> result = myDataConnection.Query<IDictionary<string, object>>(Reader, $"select id from manual limit 10").ToList();
}
...
IDictionary<string, dynamic> Reader(IDataRecord reader)
{
Dictionary<string, dynamic> values = new Dictionary<string, dynamic>(reader.FieldCount);
object[] rowValues = new object[reader.FieldCount];
int n = reader.GetValues(rowValues);
for (int j = 0; j < n; j++)
{
values.Add(reader.GetName(j), rowValues[j]);
}
return values;
}
На строке myDataConnection.Query тупит секунд 10 и вываливается с MySqlException со словами "Unable to read data from the transport connection: Попытка установить соединение была безуспешной, т.к. от другого компьютера за требуемое время не получен нужный отклик, или было разорвано уже установленное соединение из-за неверного отклика уже подключенного компьютера.."
Запрос не выполняется ни разу, в reader не заходит. Причём, если этот же код выполнять в main(), то работает как часы.
Может есть какая-то особенность работы с MySql в LinqToDB?
С постгресом нет проблем. Такой же код, но с dapper работает на ура.
L_L>На строке myDataConnection.Query тупит секунд 10 и вываливается
Так-то по-максимуму логи включить стоит, или даже просто подлкючиться во время тупняка отладчиком и попробовать посмотреть где тупит и откуда вылетает первое исключение.
По Linq2db тут отдельный форум есть, правда по историческим причинам называется неочевидно: Business Logic Toolkit
По коду я откровенного криминала не вижу (ну может только проще можно было написать), поэтому есть 2 предположения:
1. подобная ошибка возникать может если исчерпан лимит конектов к базе. Судя по всему это не наш случай, так как часть запросов до исчерпания лимитов бы отработала. Да и не помню я таких проблем конкретно с mysql
2. неясно какой из двух поддерживаемых mysql провайдеров подключен к проекту. Если официальный оракловый MySql.Data, то я настоятельно рекомендую перейти на MySqlConnector. Качество кода MySql.Data это худшее что я видел в мире ADO.NET провайдеров (даже SAP-овские не дотягивают). Для верности можно вызвать UseConnectionString(LinqToDB.ProviderName.MySqlConnector, connectionString) вместо UseMySql(connectionString).
Здравствуйте, Mace Windu, Вы писали:
MW>Здравствуйте, Lev_Limin, Вы писали:
MW>По коду я откровенного криминала не вижу (ну может только проще можно было написать), поэтому есть 2 предположения:
MW>1. подобная ошибка возникать может если исчерпан лимит конектов к базе. Судя по всему это не наш случай, так как часть запросов до исчерпания лимитов бы отработала. Да и не помню я таких проблем конкретно с mysql MW>2. неясно какой из двух поддерживаемых mysql провайдеров подключен к проекту. Если официальный оракловый MySql.Data, то я настоятельно рекомендую перейти на MySqlConnector. Качество кода MySql.Data это худшее что я видел в мире ADO.NET провайдеров (даже SAP-овские не дотягивают). Для верности можно вызвать UseConnectionString(LinqToDB.ProviderName.MySqlConnector, connectionString) вместо UseMySql(connectionString).
Использовал как LinqToDB.MySql так и LinqToDB.MySqlConnector
Тут выяснилось интересное. У меня был поднят туннель самописный(SSH.NET), и как только попробовал этот код на БД к которой есть прямой доступ, он отработал на ура.
Т.е. туннель как-то гадит. Хотя, с постгресом, через этот же туннель, всё хорошо работает.
Здравствуйте, Lev_Limin, Вы писали:
L_L>Тут выяснилось интересное. У меня был поднят туннель самописный(SSH.NET), и как только попробовал этот код на БД к которой есть прямой доступ, он отработал на ура. L_L>Т.е. туннель как-то гадит. Хотя, с постгресом, через этот же туннель, всё хорошо работает.
Здравствуйте, Mace Windu, Вы писали:
MW>Здравствуйте, Lev_Limin, Вы писали:
MW>По коду я откровенного криминала не вижу (ну может только проще можно было написать), поэтому есть 2 предположения:
MW>1. подобная ошибка возникать может если исчерпан лимит конектов к базе. Судя по всему это не наш случай, так как часть запросов до исчерпания лимитов бы отработала. Да и не помню я таких проблем конкретно с mysql MW>2. неясно какой из двух поддерживаемых mysql провайдеров подключен к проекту. Если официальный оракловый MySql.Data, то я настоятельно рекомендую перейти на MySqlConnector. Качество кода MySql.Data это худшее что я видел в мире ADO.NET провайдеров (даже SAP-овские не дотягивают). Для верности можно вызвать UseConnectionString(LinqToDB.ProviderName.MySqlConnector, connectionString) вместо UseMySql(connectionString).
Проблема никуда не делась =(
Есть background(hangfire) метод в начале которого идёт подготовительная работа, всякое читается из двух баз(mysql и pgsql). И всё работает отлично.
Дальше идёт foreach цикл
ITable<Layer> layer = _mapContext.GetLayer(layerId);
IQueryable<Layer> page = layer.Take(pageSize);
int i = 0;
foreach (Layer feature in page.AsEnumerable().WithProgress(progress, featureCount))
{
var rowId = feature.RowId;
DataParameter param = new DataParameter("@id", rowId, DataType.Int32);
var queryResult = _objectsContext.Query(query, param);
}
_objectContext это класс наследованный от DataConnection.
В классе есть метод
public IDictionary<string, object> Query(string query, DataParameter param)
{
IDictionary<string, object> result = _dbContext.Query<IDictionary<string, object>>(DataReader.Reader, query, new { param }).SingleOrDefault();
return result;
}
Делал всё по документации LinqToDB, где рассказывается про DataConnection в AspDonNetCore приложениях.
Первая итерация проходит нормально, а вторая вылетает с Command timeout, так как сервер разорвал уже открытое соединение.
Причём, перед циклом, таких запросов хоть сотню воткни, один за одним, и всё пашет.
Возможно я как-то не так работаю с DataConnection и его методом Query.
1. Что за объект _mapContext? Он как то связан с _objectsContext? например одним конектом к базе.
2. Что делает WithProgress?
3. Проблема возникает независимо от наличия ssh?
Если можно сделать небольшой тестовый проект, который воспроизводит проблему — будет супер.
Я попробовал примерно воспроизвести — вроде как всё работает. Проблема есть только если mapContext и objectContext это один и тот же инстанс DataConnection
'Cannot set MySqlCommand.CommandText when there is an open DataReader for this command; it must be closed first.'
Короче, проблема в стиле "Семён Семёныч" — DataConnection который "создаётся" через DI, это один и тот же объект.
Как только стал создавать отдельный DataConnection проблема сразу улетучилась.
Короче, проблема в стиле "Семён Семёныч" — DataConnection который "создаётся" через DI, это один и тот же объект.
Как только стал создавать отдельный DataConnection проблема сразу улетучилась.