Проблема асинхронности в Mysql с использованием C # Winform

#c# #winforms

#c# #winforms

Вопрос:

Я исправил это и искал много веб-сайтов, чтобы получить ответ, но не смог. Если вы можете помочь мне исправить это или в чем причина, по которой этот код не будет работать? Я новичок в этом асинхронном процессе. может быть, здесь есть хорошие ребята, которые могут помочь мне или упростить мой код.

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

 public async Task SearchRecord()
    {
        await Task.Run(async () =>
        {
            try
            {
                Invoke((MethodInvoker)delegate
                {
                    _route.Enabled = false;
                    _delete.Enabled = false;
                });
                conn.Close();
                await conn.OpenAsync();
                //For load only
  

Когда я запускаю это на локальном хосте, все работает нормально. но приведенный ниже код не будет работать.

                 cmd = new MySqlCommand("SELECT record_tbl.ctrl_num as ctrl_num, record_tbl.sender as sender, record_tbl.subject as subject,record_tbl.serial as serial,record_tbl.Doctype as Doctype, record_tbl.dateofletter as dateofletter, record_tbl.dateofentry as dateofentry, status_tbl.status as status  from record_tbl, status_tbl where (sender LIKE '%@Search%' or subject LIKE '%@Search%' or serial LIKE '%@Search%' or Doctype LIKE '%@Search%') AND (record_tbl.ctrl_num = status_tbl.ctrl_num AND status_tbl.status = 'DRAFT' and record_tbl.receiver = '"   Properties.Settings.Default.Name   "')", conn);
                cmd.Parameters.AddWithValue("@Search", _search.Text);
                readinfo = await cmd.ExecuteReaderAsync();
                while (readinfo.Read())
                {
                    if (readinfo.HasRows)
                    {
                        Invoke((MethodInvoker)delegate
                        {
                            //_edit.Enabled = true;
                            _route.Enabled = true;
                            _delete.Enabled = true;

                            Data.Add(new AccountData()
                            {
                                Control = readinfo.GetInt32("ctrl_num"),
                                Sender = readinfo.GetString("sender"),
                                Subject = readinfo.GetString("subject"),
                                Serial = readinfo.GetString("serial"),
                                Category = readinfo.GetString("doctype"),
                                Dateofletter = readinfo.GetDateTime("dateofletter").ToString("yyyy/MM/dd", CultureInfo.GetCultureInfo("en-US")),
                                Dateofentry = readinfo.GetDateTime("dateofentry").ToString("yyyy/MM/dd", CultureInfo.GetCultureInfo("en-US")),
                                Status = readinfo.GetString("status")
                            });

                        });

                    }
                    else
                    {

                    }

                }


                conn.Close();
            }

            catch (Exception s)

            {

                MessageBox.Show(s.Message);
                Invoke((MethodInvoker)delegate
                {
                    Error.Visible = true;
                    _route.Enabled = false;
                    _delete.Enabled = false;
                });
                conn.Close();
            }
            finally
            {

            }
        }).ConfigureAwait(true);
  

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

1. Обратите внимание, что строка в вашем вопросе начинается с > уценки для цитаты (кто-то еще сказал это, это сообщение об ошибке, которое вы получили, это дословная копия из документации и т. Д.). Я удалил их из вашего вопроса, поскольку цитирование себя странно.

2. «не будет работать» слишком расплывчато. Вы получаете сообщение об ошибке? Что?

3. я не очень хорошо говорю по-английски. мои извинения. 🙁

4. When I run this on Localhost it works fine. это вообще не работает нормально. Вы запускаете задачу только для того, чтобы немедленно вернуться к потоку пользовательского Invoke интерфейса. Даже после этого вы используете эту задачу для ожидания другой задачи. Ни один пример или учебник не настолько сложен, что должно быть признаком того, что что-то не так

5.Для начала полностью удалите Task.Run . await продолжение.OpenAsync()` уже ожидает завершения удаленной задачи без блокировки. После удаления Task.Run вам больше не нужно Invoke . Используйте using блок для соединения вместо того, чтобы закрывать его вручную. using закроет соединение даже в тех случаях, когда finally оно не будет вызвано

Ответ №1:

Правильный способ написания этого кода :

 public async Task SearchRecord()
{
    _route.Enabled = false;
    _delete.Enabled = false;
    var sql=@"SELECT record_tbl.ctrl_num as ctrl_num, record_tbl.sender as sender, record_tbl.subject as subject,record_tbl.serial as serial,record_tbl.Doctype as Doctype, record_tbl.dateofletter as dateofletter, record_tbl.dateofentry as dateofentry, status_tbl.status as status  
 from record_tbl, status_tbl 
 where (sender LIKE '%@Search%' or subject LIKE '%@Search%' or serial LIKE '%@Search%' or Doctype LIKE '%@Search%') 
       AND (record_tbl.ctrl_num = status_tbl.ctrl_num 
            AND status_tbl.status = 'DRAFT' 
            and record_tbl.receiver = @receiver)";

    try
    {
        using(var conn=new MySqlConnection(...))
        using(var cmd=new MySqlCommand(sql,conn);
        {
                
            cmd.Parameters.AddWithValue("@Search", _search.Text);
            cmd.Parameters.AddWithValue("@receiver", Properties.Settings.Default.Name);
        
            //Open the connection only when needed
            await conn.OpenAsync();
            using(var readinfo = await cmd.ExecuteReaderAsync())
            {
                while (readinfo.Read())
                {
                    Data.Add(new AccountData(){...});
                }

                _route.Enabled = true;
                _delete.Enabled = true;
            }
        }
    }
    catch(Exception exc)
    {
        //Log the error before showing it, just in case
        LogTheError(exc.ToString());

        MessageBox.Show(exc.Message);
        Error.Visible = true;
    }
}
  

Используя библиотеку, подобную Dapper, это можно упростить до :

 public async Task SearchRecord()
{
    _route.Enabled = false;
    _delete.Enabled = false;
    var sql=@"SELECT ...";

    try
    {
        using(var conn=new MySqlConnection(...))
        {
            IEnumerable<AccountData> results=await QueryAsync<AccountData>(sql, 
                  _search.Text, 
                  Properties.Settings.Default.Name);
        
            Data.AddRange(results);
                
            _route.Enabled = true;
            _delete.Enabled = true;
        }    
    }
    catch(Exception exc)
    {
        //Log the error before showing it, just in case
        LogTheError(exc.ToString());

        MessageBox.Show(exc.Message);
        Error.Visible = true;
    }
}
  

Объяснение

Нет необходимости Task.Run запускать и ожидать асинхронные операции. Асинхронные операции уже выполняются либо в другом потоке, либо вообще не используют поток. Ввод-вывод в Windows всегда асинхронный и выполняется ОС. Это включает в себя запись на диск или обмен данными с базой данных по сети.

await не запускает асинхронную операцию, она ожидает уже выполняемой, не блокируя вызывающий поток. После await завершения выполнение возвращается к исходному потоку. В случае настольных приложений это поток пользовательского интерфейса.

Invoke() возвращает выполнение в поток пользовательского интерфейса. Однако при использовании это не требуется await , поскольку выполнение уже вернулось в поток пользовательского интерфейса.

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

Это может даже привести к взаимоблокировкам, если два клиента в конечном итоге будут ждать, пока другой освободит свои заблокированные строки. Если, например, два приложения прочитают всю таблицу, а затем попытаются выполнить в нее запись, они, вероятно, перейдут в тупик, потому что каждое из них уже заняло общие блокировки для всех строк таблицы.

Нет причин использовать глобальные подключения. ADO.NET использует объединение соединений, чтобы сделать открытие и закрытие соединений как можно более дешевыми. Когда соединение закрывается, оно не удаляется. Вместо этого ADO.NET сбрасывает его и помещает обратно в пул повторно используемых подключений. Таким образом, открытие нового соединения происходит мгновенно.