Получить текущее подключение с базой

Обсуждение Stimulsoft Reports.NET
Аватара пользователя
t0pdevice
Сообщения: 107
Зарегистрирован: 15 авг 2016, 09:59

Re: Получить текущее подключение с базой

Сообщение t0pdevice »

Спасибо.

Сделал так:

Код: Выделить всё

            foreach (StiDataSource dataSource in _report.DataSources)
            {
                dataSource.Disconnect();
            }

            foreach (StiData dataStore in _report.DataStore)
            {
                if (dataStore.Data is NpgsqlConnection connection)
                    connection.Close();
            }
Но не особо помогло. Запрос все равно выполняется после этого на базе.
Возможно, нужно выполнять Cancel() для выполняемого запроса (NpgsqlCommand).
Но таких данных я из отчёта не могу найти, где получить.
Аватара пользователя
t0pdevice
Сообщения: 107
Зарегистрирован: 15 авг 2016, 09:59

Re: Получить текущее подключение с базой

Сообщение t0pdevice »

Если попробовать отменить запрос через тот же pgAdmin, то на клиенте потом появляется ошибка о том, что передача данных разорвана, потому что Render() у отчёта до сих пор выполнял запрос:

Код: Выделить всё

Npgsql.NpgsqlException (0x80004005): Exception while reading from stream ---> System.IO.EndOfStreamException: Попытка чтения после конца потока.
в Npgsql.ReadBuffer.d__27.MoveNext()
в Npgsql.ReadBuffer.d__27.MoveNext()
--- Конец трассировка стека из предыдущего расположения, где возникло исключение ---
в System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
в System.Runtime.CompilerServices.TaskAwaiter.GetResult()
в Npgsql.NpgsqlConnector.d__155.MoveNext()
--- Конец трассировка стека из предыдущего расположения, где возникло исключение ---
в System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
в System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
в System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
в Npgsql.NpgsqlConnector.d__154.MoveNext()
--- Конец трассировка стека из предыдущего расположения, где возникло исключение ---
в System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
в System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
в System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
в Npgsql.NpgsqlDataReader.d__32.MoveNext()
--- Конец трассировка стека из предыдущего расположения, где возникло исключение ---
в System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
в System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
в Npgsql.NpgsqlDataReader.NextResult()
в Npgsql.NpgsqlCommand.d__71.MoveNext()
--- Конец трассировка стека из предыдущего расположения, где возникло исключение ---
в System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
в System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
в System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
в Npgsql.NpgsqlCommand.d__92.MoveNext()
--- Конец трассировка стека из предыдущего расположения, где возникло исключение ---
в System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
в System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
в System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
в Npgsql.NpgsqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
в System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader(CommandBehavior behavior)
в System.Data.Common.DbDataAdapter.FillInternal(DataSet dataset, DataTable[] datatables, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior)
в System.Data.Common.DbDataAdapter.Fill(DataTable[] dataTables, Int32 startRecord, Int32 maxRecords, IDbCommand command, CommandBehavior behavior)
в System.Data.Common.DbDataAdapter.Fill(DataTable dataTable)
в Stimulsoft.Report.Dictionary.StiDataAdapterHelper.Fill(StiDictionary dictionary, DbDataAdapter dataAdapter, DataTable dataTable, Boolean schemaOnly) в D:\Stimulsoft\Stimulsoft.Reports\Stimulsoft.Report\Dictionary\StiDataAdapterHelper.cs:строка 67
в Stimulsoft.Report.Dictionary.StiSqlSource.RetrieveData(Boolean schemaOnly) в D:\Stimulsoft\Stimulsoft.Reports\Stimulsoft.Report\Dictionary\DataSources\Sql\StiSqlSource.cs:строка 425
в Stimulsoft.Report.Dictionary.StiSqlAdapterService.ConnectDataSourceToData(StiDictionary dictionary, StiDataSource dataSource, Boolean loadData) в D:\Stimulsoft\Stimulsoft.Reports\Stimulsoft.Report\Dictionary\Adapters\Sql\StiSqlAdapterService.cs:строка 401
в Stimulsoft.Report.Dictionary.StiDataSource.Connect(StiDataCollection datas, Boolean loadData) в D:\Stimulsoft\Stimulsoft.Reports\Stimulsoft.Report\Dictionary\DataSources\StiDataSource.cs:строка 1341
в Stimulsoft.Report.Dictionary.StiDataSourcesCollection.Connect(StiDataCollection datas, Boolean loadData) в D:\Stimulsoft\Stimulsoft.Reports\Stimulsoft.Report\Dictionary\DataSources\StiDataSourcesCollection.cs:строка 343
в Stimulsoft.Report.Dictionary.StiDataSourcesCollection.Connect(Boolean loadData) в D:\Stimulsoft\Stimulsoft.Reports\Stimulsoft.Report\Dictionary\DataSources\StiDataSourcesCollection.cs:строка 322
в Stimulsoft.Report.Dictionary.StiDictionary.Connect(Boolean loadData, List`1 dataSources) в D:\Stimulsoft\Stimulsoft.Reports\Stimulsoft.Report\Dictionary\StiDictionary.cs:строка 1511
в Stimulsoft.Report.Engine.StiRenderProviderV2.ConnectToData(StiReport report) в D:\Stimulsoft\Stimulsoft.Reports\Stimulsoft.Report\Engine\EngineV2\StiRenderProviderV2.cs:строка 716
в Stimulsoft.Report.Engine.StiRenderProviderV2.Render(StiReport report, StiRenderState state) в D:\Stimulsoft\Stimulsoft.Reports\Stimulsoft.Report\Engine\EngineV2\StiRenderProviderV2.cs:строка 410
в Stimulsoft.Report.Engine.StiReportV2Builder.RenderSingleReport(StiReport masterReport, StiRenderState renderState) в D:\Stimulsoft\Stimulsoft.Reports\Stimulsoft.Report\Engine\EngineV2\Builders\StiReportV2Builder.cs:строка 144
в Stimulsoft.Report.StiReport.RenderReport(StiRenderState renderState) в D:\Stimulsoft\Stimulsoft.Reports\Stimulsoft.Report\StiReport.Render.cs:строка 350
в Stimulsoft.Report.StiReport.Render(StiRenderState renderState, StiGuiMode guiMode) в D:\Stimulsoft\Stimulsoft.Reports\Stimulsoft.Report\StiReport.Render.cs:строка 210
в Stimulsoft.Report.StiReport.Render(StiRenderState renderState) в D:\Stimulsoft\Stimulsoft.Reports\Stimulsoft.Report\StiReport.Render.cs:строка 97
в Stimulsoft.Report.StiReport.Render(Boolean showProgress, Int32 fromPage, Int32 toPage) в D:\Stimulsoft\Stimulsoft.Reports\Stimulsoft.Report\StiReport.Render.cs:строка 89
в Stimulsoft.Report.StiReport.Render(Boolean showProgress) в D:\Stimulsoft\Stimulsoft.Reports\Stimulsoft.Report\StiReport.Render.cs:строка 79
в Render_DoWork(Object sender, DoWorkEventArgs e)
Аватара пользователя
t0pdevice
Сообщения: 107
Зарегистрирован: 15 авг 2016, 09:59

Re: Получить текущее подключение с базой

Сообщение t0pdevice »

Посмотрел, что у connection, полученного через _report.DataStore в State стоит Closed (то есть оно закрыто) и также ProcessID нет.
Сам DataStore заполняется после того, как происходит вызов Dictionary.Synchronize(), но я отслеживал через дебаг, что после заполнения DataStore, даже после вызова Render, у него все равно State = Closed.
Поэтому и закрытие, что я выше указал никак не помогло, так как соединение уже закрытое.

Получается в DataStore хранится не активное подключение, а лишь его настройки.
Aleksey
Сообщения: 2906
Зарегистрирован: 22 апр 2010, 06:57

Re: Получить текущее подключение с базой

Сообщение Aleksey »

Здравствуйте,

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

Спасибо.
Аватара пользователя
t0pdevice
Сообщения: 107
Зарегистрирован: 15 авг 2016, 09:59

Re: Получить текущее подключение с базой

Сообщение t0pdevice »

Во вложении простой проект, который показывает саму суть.
Поменяйте в Get_Report() параметры подключения к PostgreSQL базе через NpgsqlConnectionStringBuilder.
Отчёт берется из конечной директории Report.mrt, его суть проста, там просто эмуляция выполнения через pg_sleep (30 секунд).

1. Запускаем выполнение отчёта. Заходим в pgAdmin 3 - "Инструменты" - "Состояние сервера".
2. Видим, что с ApplicationName - "Stimulsoft" выполняется запрос.
3. В приложении нажимаем "Отмена", что должно закрыть форму, уничтожить отчет и разорвать все соединения с базой и выполняющиеся запросы.
4. Смотрим в "Состоянии сервера" запрос еще выполняется.
5. Выделяем наш запрос и жмём в меню "Завершить процесс".
6. Запрос отменяется, а приложение выдаёт ошибку "Exception while reading from stream".
Вложения
Stimulsoft.zip
(2.07 МБ) 223 скачивания
Аватара пользователя
t0pdevice
Сообщения: 107
Зарегистрирован: 15 авг 2016, 09:59

Re: Получить текущее подключение с базой

Сообщение t0pdevice »

Удалось воспроизвести?
Aleksey
Сообщения: 2906
Зарегистрирован: 22 апр 2010, 06:57

Re: Получить текущее подключение с базой

Сообщение Aleksey »

Здравствуйте,

Спасибот за пример. Воспроизвести получилось.
К сожалению, не получится так из кода закрыть текущее соединение. В данном случае, при рендеринге отчета вызвается метод dataAdapter.Fill(dataTable);
на котором и происходит данная ошибка, либо ожидание завершения выполнения либо ошибка о закрытом соединение.

В вашем случае, вы можете либо предварительно готовить данные и регестрировать их через RagData() метод. В данном случае, вы можете добавлять необходимые проверки еще до рендеринга отчета.

И втрой вариант, реализовать свои методы отмены или передачи конекшена через свой кастомный адаптер для PostgreSQL
http://admin.stimulsoft.com/downloads/d ... greSQL.zip

https://social.msdn.microsoft.com/Forum ... arpgeneral

Спасибо.
Аватара пользователя
t0pdevice
Сообщения: 107
Зарегистрирован: 15 авг 2016, 09:59

Re: Получить текущее подключение с базой

Сообщение t0pdevice »

Спасибо за информацию.

Да, я понимаю из-за чего ошибка. У PostgreSQL при отмене запроса на сервере приходит ошибка:
57014: canceling statement due to user request
По сути можно её обрабатывать в catch (PostgresException) для dataAdapter.Fill.
В вашем случае, вы можете либо предварительно готовить данные и регестрировать их через RagData() метод. В данном случае, вы можете добавлять необходимые проверки еще до рендеринга отчета.
Такой вариант рассматривался, но с точки зрения поддержки он не очень удобен, потому что надо постоянно актуализировать колонки в источнике при изменении каких-то данных с процедуры (новые колонки, к примеру). Когда запрос вшит в отчёт - это сделать проще для специального сотрудника, который имеет доступ, к примеру, только к редактору отчётов, а не к исходникам процедур и программы.
Aleksey
Сообщения: 2906
Зарегистрирован: 22 апр 2010, 06:57

Re: Получить текущее подключение с базой

Сообщение Aleksey »

Здравствуйте,

> По сути можно её обрабатывать в catch (PostgresException) для dataAdapter.Fill.

Добавили в список задач, посмотрим что можно там сделать.

Спасибо.
aikidos
Сообщения: 1
Зарегистрирован: 10 апр 2018, 11:13

Re: Получить текущее подключение с базой

Сообщение aikidos »

Aleksey писал(а):И втрой вариант, реализовать свои методы отмены или передачи конекшена через свой кастомный адаптер для PostgreSQL
Здравствуйте. Подключение к базе я смог получить, но я не могу "поймать" создание команд (IDbCommand). Я пробовал написать классы, унаследованные от StiOracleConnector / StiOracleAdapterService / StiOracleDatabase, и наблюдать за вызовом virtual-методов, но никто из них не занимается заполнением StiDataSource.

Суть проблемы: узнать какие запросы отправляет отчёт.

Заранее благодарен за помощь.

Вот, кстати, реализация получения текущего подключения (через событие DbConnectionBase.StateChange можно отлавливать момент открытия соединения). Вдруг кому-то пригодится.

Код: Выделить всё

public class MyDatabase : StiOracleDatabase
{
    protected override string DataAdapterType { get; } = typeof(MyAdapter).FullName;

    public MyDatabase()
        : this(string.Empty, string.Empty)
    {
    }

    public MyDatabase(string name, string connectionString)
        : base(name, connectionString)
    {
    }

    public MyDatabase(string name, string alias, string connectionString)
        : base(name, alias, connectionString)
    {
    }

    public MyDatabase(string name, string alias, string connectionString, bool promptUserNameAndpassword)
        : base(name, alias, connectionString, promptUserNameAndpassword)
    {
    }

    public MyDatabase(string name, string alias, string connectionString, bool promptUserNameAndpassword, string key)
        : base(name, alias, connectionString, promptUserNameAndpassword, key)
    {
    }

    public override StiSqlAdapterService GetDataAdapter() => new MyAdapter();
}
Адаптер:

Код: Выделить всё

public class MyAdapter : StiOracleAdapterService
{
    public override void CreateConnectionInDataStore(StiDictionary dictionary, StiSqlDatabase database)
    {
        base.CreateConnectionInDataStore(dictionary, database);

        // Подключения можно получить из DataStore:
        var connection = dictionary.DataStore[0].Data as OracleConnection;
    }
}
Добавление своей реализации:

Код: Выделить всё

StiReport.Dictionary.Databases.Add(new MyDatabase(name, connectionString));
Ответить