LinqToDb
От: Lev_Limin  
Дата: 24.12.20 18:44
Оценка:
До недавнего времени я, для работы с БД, использовал 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 работает на ура.
Re: LinqToDb
От: hi_octane Беларусь  
Дата: 24.12.20 23:27
Оценка:
L_L>На строке myDataConnection.Query тупит секунд 10 и вываливается
Так-то по-максимуму логи включить стоит, или даже просто подлкючиться во время тупняка отладчиком и попробовать посмотреть где тупит и откуда вылетает первое исключение.

По Linq2db тут отдельный форум есть, правда по историческим причинам называется неочевидно: Business Logic Toolkit
Re: LinqToDb
От: Mace Windu  
Дата: 25.12.20 09:27
Оценка:
Здравствуйте, Lev_Limin, Вы писали:

По коду я откровенного криминала не вижу (ну может только проще можно было написать), поэтому есть 2 предположения:

1. подобная ошибка возникать может если исчерпан лимит конектов к базе. Судя по всему это не наш случай, так как часть запросов до исчерпания лимитов бы отработала. Да и не помню я таких проблем конкретно с mysql
2. неясно какой из двух поддерживаемых mysql провайдеров подключен к проекту. Если официальный оракловый MySql.Data, то я настоятельно рекомендую перейти на MySqlConnector. Качество кода MySql.Data это худшее что я видел в мире ADO.NET провайдеров (даже SAP-овские не дотягивают). Для верности можно вызвать UseConnectionString(LinqToDB.ProviderName.MySqlConnector, connectionString) вместо UseMySql(connectionString).
Re[2]: LinqToDb
От: Lev_Limin  
Дата: 26.12.20 10:17
Оценка:
Здравствуйте, 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), и как только попробовал этот код на БД к которой есть прямой доступ, он отработал на ура.
Т.е. туннель как-то гадит. Хотя, с постгресом, через этот же туннель, всё хорошо работает.
Re[3]: LinqToDb
От: Mace Windu  
Дата: 26.12.20 11:08
Оценка:
Здравствуйте, Lev_Limin, Вы писали:

L_L>Тут выяснилось интересное. У меня был поднят туннель самописный(SSH.NET), и как только попробовал этот код на БД к которой есть прямой доступ, он отработал на ура.

L_L>Т.е. туннель как-то гадит. Хотя, с постгресом, через этот же туннель, всё хорошо работает.

по ssh.net у Mysqlconnector целый мануал по настройке есть: https://mysqlconnector.net/tutorials/connect-ssh/, может в этом дело
Re[2]: LinqToDb
От: Lev_Limin  
Дата: 06.01.21 14:12
Оценка:
Здравствуйте, 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;
}


Класс этот подключаю в Startup
services.AddLinqToDbContext<MySqlDbContext>((provider, options) =>
{
    options
        .UseConnectionString(LinqToDB.ProviderName.MySqlConnector, Configuration.GetConnectionString("MyConnectionString"))
        .UseDefaultLogging(provider);
});


Делал всё по документации LinqToDB, где рассказывается про DataConnection в AspDonNetCore приложениях.

Первая итерация проходит нормально, а вторая вылетает с Command timeout, так как сервер разорвал уже открытое соединение.
Причём, перед циклом, таких запросов хоть сотню воткни, один за одним, и всё пашет.

Возможно я как-то не так работаю с DataConnection и его методом Query.
Re[3]: LinqToDb
От: Mace Windu  
Дата: 07.01.21 10:22
Оценка:
Здравствуйте, Lev_Limin, Вы писали:

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.'

но это известное ограничение ado.net, которое мы в следующем релизе планируем частично снять где провайдеры позволяют https://github.com/linq2db/linq2db/pull/2728

На первый взгляд где-то идет нарушение контракта работы с ADO.NET провайдером, но где — понять не могу пока без рабочего кода.
Re[3]: LinqToDb
От: Danchik Украина  
Дата: 09.01.21 20:11
Оценка:
Здравствуйте, Lev_Limin, Вы писали:

Вот это: page.AsEnumerable() попробуте заменить на page.ToList()

И у меня чувство что вы делаете что-то, что на linq2db делается с полпинка автоматически.
Re: LinqToDb
От: LevLimin Россия  
Дата: 14.01.21 08:40
Оценка:
Здравствуйте, Lev_Limin, Вы писали:

Короче, проблема в стиле "Семён Семёныч" — DataConnection который "создаётся" через DI, это один и тот же объект.
Как только стал создавать отдельный DataConnection проблема сразу улетучилась.
Lev Limin
Re: LinqToDb
От: LevLimin Россия  
Дата: 14.01.21 09:05
Оценка:
Здравствуйте, Lev_Limin, Вы писали:

Короче, проблема в стиле "Семён Семёныч" — DataConnection который "создаётся" через DI, это один и тот же объект.
Как только стал создавать отдельный DataConnection проблема сразу улетучилась.
Lev Limin
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.