RussianLDP Рейтинг@Mail.ru
WebMoney: 
WMZ Z294115950220 
WMR R409981405661 
WME E134003968233 
Visa 
4274 3200 2453 6495 

Глава 5. Программирование Connector/NET

MySQL Connector/NET включает несколько классов, которые используются, чтобы соединиться с базой данных, выполнить запросы и управлять результатами запроса.

Следующее это главные классы Connector/NET:

  • MySqlConnection: Представляет открытую связь с базой данных MySQL.

  • MySqlConnectionStringBuilder: Помогает в создании строки подключения, выставляя варианты связи как свойства.

  • MySqlCommand: Представляет SQL-оператор, чтобы выполнить для базы данных MySQL.

  • MySqlCommandBuilder: Автоматически производит команды единственной таблицы, используемые, чтобы урегулировать изменения, внесенные в DataSet со связанной базой данных MySQL.

  • MySqlDataAdapter: Представляет ряд команд данных и соединения с базой данных, которые используются, чтобы заполнить набор данных и обновить базу данных MySQL.

  • MySqlDataReader: Обеспечивает средство чтения потока для строк от базы данных MySQL.

  • MySqlException: Исключение, которое брошено, когда MySQL возвращает ошибку.

  • MySqlHelper: Класс помощника, который облегчает работу с поставщиком.

  • MySqlTransaction: Представляет транзакцию SQL, которая будет сделана в базе данных MySQL.

В следующих разделах вы узнаете о некоторых случаях общего использования для Connector/NET, включая обработку BLOB, обработку даты и использование Connector/NET с общими инструментами, такими как Crystal Reports.

5.1. Использование GetSchema на связи

Метод GetSchema() объекта связи может использоваться, чтобы восстановить информацию о схеме о базе данных, в настоящее время применяемой. Информация о схеме возвращена в форме DataTable. Информация о схеме организована во многие коллекции. Различные формы метода GetSchema() могут использоваться в зависимости от запрошенной информации. Есть три формы метода GetSchema():

  • GetSchema(): возвратит список доступных коллекций.

  • GetSchema(String): вернет информацию по поводу коллекции, названной в строковом параметре. Если последовательность MetaDataCollections, список всех доступных коллекций возвращен. Это совпадает с запросом GetSchema() без любых параметров.

  • GetSchema(String, String[]): первый строковый параметр представляет имя коллекции, второй параметр представляет строковый массив ограничения. Значения ограничения задают объем данных, который будет возвращен. Значения ограничения объяснены более подробно в Microsoft .NET documentation.

Коллекции

Коллекции могут быть сгруппированы в два типа: коллекции, которые характерны для всех провайдеров данных и коллекции, определенные для конкретного поставщика.

Общие Коллекции. Следующие коллекции характерны для всех провайдеров данных:

  • MetaDataCollections

  • DataSourceInformation

  • DataTypes

  • Restrictions

  • ReservedWords

Определенные для поставщика коллекции. Следующее коллекции, в настоящее время обеспечиваемые Connector/NET, в дополнение к общим коллекциям, показанным ранее:

  • Databases

  • Tables

  • Columns

  • Users

  • Foreign Keys

  • IndexColumns

  • Indexes

  • Foreign Key Columns

  • UDF

  • Views

  • ViewColumns

  • Procedure Parameters

  • Procedures

  • Triggers

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

using System;
using System.Data;
using System.Text;
using MySql.Data;
using MySql.Data.MySqlClient;

namespace ConsoleApplication2
{
  class Program
  {
    private static void DisplayData(System.Data.DataTable table)
    {
      foreach (System.Data.DataRow row in table.Rows)
      {
        foreach (System.Data.DataColumn col in table.Columns)
        {
          Console.WriteLine("{0} = {1}", col.ColumnName, row[col]);
        }
        Console.WriteLine("============================");
      }
    }

    static void Main(string[] args)
    {
      string connStr = "server=localhost;user=root;database=world;port=3306;password=******";
      MySqlConnection conn = new MySqlConnection(connStr);
      try
      {
        Console.WriteLine("Connecting to MySQL...");
        conn.Open();
        DataTable table = conn.GetSchema("MetaDataCollections");
        // DataTable table = conn.GetSchema("UDF");
        DisplayData(table);
        conn.Close();
      }
      catch (Exception ex)
      {
        Console.WriteLine(ex.ToString());
      }
      Console.WriteLine("Done.");
    }
  }
}

Дополнительная информация о методе GetSchema() и коллекции схемы могут быть найдены в Microsoft .NET documentation.

5.2. Применение MySqlCommand

MySqlCommand имеет свойства CommandText и CommandType, связанные с ним. CommandText будет обработан по-другому в зависимости от настройки CommandType. CommandType может быть одним из:

  • Text: текст команды SQL (по умолчанию).

  • StoredProcedure: название хранимой процедуры.

  • TableDirect: название таблицы.

Пор умолчанию CommandType = Text, используется для выполнения запросов и других команд SQL. Пример этого может быть найден в разделе 6.1.2.

Если CommandType = StoredProcedure, CommandText установлен к названию хранимой процедуры.

Если CommandType = TableDirect, все строки и колонки названной таблицы будут возвращены, когда вы вызовете один из методов Execute. В действительности эта команда выполняет SELECT * на определенной таблице. Свойство CommandText устанавливается в название таблицы. Это проиллюстрировано следующим фрагментом кода:

...
MySqlCommand cmd = new MySqlCommand();
cmd.CommandText = "mytable";
cmd.Connection = someConnection;
cmd.CommandType = CommandType.TableDirect;
MySqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
  Console.WriteLn(reader[0], reader[1]...);
}
...

Примеры использования CommandType StoredProcedure есть в разделе 5.6.

Командам можно привязать тайм-аут. Это полезно, поскольку вы не можете хотеть ситуацию, когда команда, занимает чрезмерное время. Тайм-аут может быть установлен, используя свойство CommandTimeout. Следующий фрагмент кода устанавливает тайм-аут в одну минуту:

MySqlCommand cmd = new MySqlCommand();
cmd.CommandTimeout = 60;

Значение по умолчанию составляет 30 секунд. 0 задает неопределенное время ожидания. Чтобы изменить тайм-аут по умолчанию, используйте выбор строки подключения Default Command Timeout.

Connector/NET поддерживает тайм-аут, выровненные по обработке Microsoft SqlCommand.CommandTimeout. Это свойство задает общий тайм-аут для всех сетевых чтений и записей во время выполнения команды или обработки результатов. Тайм-аут может все еще произойти в методе MySqlReader.Read после возврата первой строки и не включает пользовательское время обработки, только операции IO.

Более подробная информация об этом может быть найдена в соответствующей Microsoft documentation.

5.3. Обзор идентификации Connector/NET

MySQL Connector/NET осуществляет множество плагинов идентификации, которые MySQL Server может вызвать, чтобы подтвердить подлинность пользователя. Идентификация позволяет серверу определить, какой плагин применяется, на основе имени пользователя и имени хоста, которое ваше приложение передает серверу, устанавливая связь. Для полного описания процесса аутентификации см. Pluggable Authentication.

Connector/NET обеспечивает следующие плагины идентификации и методы:

  • mysql_native_password.

    Поддержано для всех версий Connector/NET.

  • sha256_password

    Минимальная версия: Connector/NET 8.0.11.

    Поддержано для классических связей протокола и для X-протокола MySQL. Для получения дополнительной информации об использовании механизма MYSQL41 с X Protocol см. опцию Auth .

  • caching_sha2_password

    Минимальная версия: Connector/NET 6.10.7 и 8.0.11 только для классических связей протокола MySQL.

  • authentication_windows_client

    Поддержано для всех версий Connector/NET.

  • authentication_ldap_sasl_client

    Минимальная версия: Connector/NET 8.0.22 только для классических связей протокола MySQL.

    SASL-аутентификация LDAP для Connector/NET требует Enterprise Edition MySQL. Протокол аутентификации SASL (использующий (метод аутентификации SCRAM-SHA-1), относится к клиентам, работающим в Windows и Linux, но не в macOS.

  • mysql_clear_password

    Минимальная версия: Connector/NET 8.0.22 только для классических связей протокола MySQL.

    Требует безопасного соединения с сервером, который удовлетворяет любым условиям для клиента:

    • У опции связи SslMode есть значение кроме None (по умолчанию Preferred).

    • Опция ConnectionProtocol установлена в unix для сокетов Unix.

5.3.1. Использование Windows Native Authentication Plugin

MySQL Connector/NET можнт подтвердить подлинность серверу MySQL, используя Windows Native Authentication Plugin. Пользователи, которые авторизовались в Windows, могут соединиться из программы клиента MySQL с сервером на основе информации в их среде, не определяя дополнительный пароль. Для информации об использовании плагина идентификации, посмотрите Windows Pluggable Authentication.

Интерфейс соответствует объекту MySql.Data.MySqlClient. Чтобы позволить его, передайте Integrated Security в строке подключения со значением yes или sspi.

Передача user ID опциональна. Когда аутентификация Windows настраивается, пользователь MySQL создается и формируется, чтобы использоваться аутентификацией Windows. По умолчанию этот идентификатор пользователя называют auth_windows, но он может быть определен, используя другое имя. Если имя по умолчанию используется, то передача идентификатора пользователя в строке подключения от Connector/NET не обязательна, потому что это будет использовать пользователя auth_windows. Иначе имя должно быть передано в строке подключения, используя стандартный элемент идентификатора пользователя.

5.3.2. Написание своего плагина идентификации

Опытные пользователи со специальными требованиями к защите могут создать свои собственные плагины идентификации для приложений MySQL Connector/NET. Можно расширить протокол рукопожатия, добавив нужную логику. Для информации об использовании плагинов идентификации MySQL, посмотрите Authentication Plugins и Writing Authentication Plugins.

Чтобы написать плагин идентификации, вам будет нужна ссылка на сборку MySql.Data.dll. Классы, важные для написания плагинов идентификации, доступны в пространстве имен MySql.Data.MySqlClient.Authentication.

Как плагин идентификации работает

В какой-то момент во время рукопожатия, внутреннего метода

void Authenticate(bool reset)

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

Создание класса плагина идентификации

Вы помещаете логику плагина идентификации в новом классе, полученном из MySql.Data.MySqlClient.Authentication.MySqlAuthenticationPlugin. Следующие методы доступны для перекрытия:

protected virtual void CheckConstraints()
protected virtual void AuthenticationFailed(Exception ex)
protected virtual void AuthenticationSuccessful()
protected virtual byte[] MoreData(byte[] data)
protected virtual void AuthenticationChange()
public abstract string PluginName { get; }
public virtual string GetUsername()
public virtual object GetPassword()
protected byte[] AuthData;

Следующее это краткое объяснение каждого:

/// <summary>
/// This method must check authentication method specific constraints in the
environment and throw an Exception
/// if the conditions are not met. The default implementation does nothing.
/// </summary>
protected virtual void CheckConstraints()

/// <summary>
/// This method, called when the authentication failed, provides a chance to
plugins to manage the error
/// the way they consider decide (either showing a message, logging it, etc.).
/// The default implementation wraps the original exception in a MySqlException
with an standard message and rethrows it.
/// </summary>
/// <param name="ex">The exception with extra information on the error.</param>
protected virtual void AuthenticationFailed(Exception ex)

/// <summary>
/// This method is invoked when the authentication phase was successful accepted
by the server.
/// Derived classes must override this if they want to be notified of such
condition.
/// </summary>
/// <remarks>The default implementation does nothing.</remarks>
protected virtual void AuthenticationSuccessful()

/// <summary>
/// This method provides a chance for the plugin to send more data when the
server requests so during the
/// authentication phase. This method will be called at least once, and more
than one depending upon whether the
/// server response packets have the 0x01 prefix.
/// </summary>
/// <param name="data">The response data from the server, during the
authentication phase the first time is called is null, in
subsequent calls contains the server response.</param>
/// <returns>The data generated by the plugin for server consumption.</returns>
/// <remarks>The default implementation always returns null.</remarks>
protected virtual byte[] MoreData(byte[] data)

/// <summary>
/// The plugin name.
/// </summary>
public abstract string PluginName { get; }

/// <summary>
/// Gets the user name to send to the server in the authentication phase.
/// </summary>
/// <returns>An string with the user name</returns>
/// <remarks>Default implementation returns the UserId passed from the
connection string.</remarks>
public virtual string GetUsername()

/// <summary>
/// Gets the password to send to the server in the authentication phase. This
can be a string or a
/// </summary>
/// <returns>An object, can be byte[], string or null, with the password.
</returns>
/// <remarks>Default implementation returns null.</remarks>
public virtual object GetPassword()

/// <summary>
/// The authentication data passed when creating the plugin.
/// For example in mysql_native_password this is the seed to encrypt the
password.
/// </summary>
protected byte[] AuthData;

Типовой плагин идентификации

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

  1. Создайте консольное приложение, добавив ссылку на MySql.Data.dll.

  2. Проектируйте главную программу следующим образом:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using MySql.Data.MySqlClient;
    
    namespace AuthPluginTest
    {
      class Program
      {
        static void Main(string[] args)
        {
          // Customize the connection string as necessary.
          MySqlConnection con = new MySqlConnection("server=localhost;
          database=test; user id=myuser; password=mypass");
          con.Open();
          con.Close();
        }
      }
    }
    
  3. Создайте свой класс плагина. В этом примере мы добавляем альтернативную реализацию родного плагина пароля, просто используя тот же самый код от оригинального плагина. Мы называем наш класс MySqlNativePasswordPlugin2:

    using System.IO;
    using System;
    using System.Text;
    using System.Security.Cryptography;
    using MySql.Data.MySqlClient.Authentication;
    using System.Diagnostics;
    
    namespace AuthPluginTest
    {
      public class MySqlNativePasswordPlugin2 : MySqlAuthenticationPlugin
      {
        public override string PluginName
        {
          get { return "mysql_native_password"; }
        }
    
        public override object GetPassword()
        {
          Debug.WriteLine("Calling MySqlNativePasswordPlugin2.GetPassword");
          return Get411Password(Settings.Password, AuthData);
        }
    
        /// <summary>
        /// Returns a byte array containing the proper encryption of the
        /// given password/seed according to the new 4.1.1 authentication scheme.
        /// </summary>
        /// <param name="password"></param>
        /// <param name="seed"></param>
        /// <returns></returns>
        private byte[] Get411Password(string password, byte[] seedBytes)
        {
          // if we have no password, then we just return 1 zero byte
          if (password.Length == 0) return new byte[1];
          SHA1 sha = new SHA1CryptoServiceProvider();
          byte[] firstHash = sha.ComputeHash(Encoding.Default.GetBytes(password));
          byte[] secondHash = sha.ComputeHash(firstHash);
          byte[] input = new byte[seedBytes.Length + secondHash.Length];
          Array.Copy(seedBytes, 0, input, 0, seedBytes.Length);
          Array.Copy(secondHash, 0, input, seedBytes.Length, secondHash.Length);
          byte[] thirdHash = sha.ComputeHash(input);
          byte[] finalHash = new byte[thirdHash.Length + 1];
          finalHash[0] = 0x14;
          Array.Copy(thirdHash, 0, finalHash, 1, thirdHash.Length);
          for (int i = 1; i < finalHash.Length; i++)
            finalHash[i] = (byte)(finalHash[i] ^ firstHash[i - 1]);
          return finalHash;
        }
      }
    }
    
  4. Заметьте, что реализация просто перекрывает GetPassword и обеспечивает внедрение, чтобы зашифровать пароль, используя протокол 4.1. Мы также вставляем следующую строку в GetPassword:

    Debug.WriteLine("Calling MySqlNativePasswordPlugin2.GetPassword");
    

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

  5. Позвольте новый плагин в конфигурационном файле:

    <?xml version="1.0"?>
    <configuration>
      <configSections>
        <section name="MySQL" type="MySql.Data.MySqlClient.MySqlConfiguration,
          MySql.Data"/>
      </configSections>
      <MySQL>
        <AuthenticationPlugins>
          <add name="mysql_native_password"
            type="AuthPluginTest.MySqlNativePasswordPlugin2,
            AuthPluginTest"></add>
        </AuthenticationPlugins>
      </MySQL>
      <startup><supportedRuntime version="v4.0"
        sku=".NETFramework, Version=v4.0"/>
      </startup>
    </configuration>
    
  6. Запустите приложение. В Visual Studio в окне отладки вы будете видеть сообщение Calling MySqlNativePasswordPlugin2.GetPassword.

  7. Продолжите увеличивать логику идентификации, перекрыв больше методов, если это надо.

5.4. Использование Connector/NET с кэшированием таблиц

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

Эта опция очевидна для применения и отключена по умолчанию.

Настройка

  • Чтобы позволить кэширование таблицы, надо добавить 'table cache = true' к строке подключения.

  • Произвольно, определите опцию 'Default Table Cache Age', которая представляет число секунд, которое таблица кэшировалась, прежде чем от кэшированных данных отказываются. Значение по умолчанию 60.

  • Можно включить/выключить кэширование и установить варианты кэширования во время выполнения на основе команды.

5.5. Использование Connector/NET с подготовленными запросами

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

Подготовленные запросы доступны с MySQL 4.1 и выше.

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

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

Подготовка запроса на стороне сервера по умолчанию выключена. Для ее включения добавьте к вашей строке подключения "IgnorePrepare=false".

5.5.1. Подготовка запросов в Connector/NET

Чтобы подготовить запрос, создайте объект команды и установите свойство CommandText к вашему запросу.

После входа в ваш запрос, вызовите метод Prepare объекта MySqlCommand. После того, как запрос подготовлен, добавьте параметры для каждого из динамических элементов в запросе.

После того, как вы входите в свой запрос и передаете параметры, выполните запрос, используя метод ExecuteNonQuery(), ExecuteScalar() или ExecuteReader.

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

Пример Visual Basic

Dim conn As New MySqlConnection
Dim cmd As New MySqlCommand
conn.ConnectionString = strConnection

Try
  conn.Open()
  cmd.Connection = conn
  cmd.CommandText = "INSERT INTO myTable VALUES(NULL, @number, @text)"
  cmd.Prepare()
  cmd.Parameters.AddWithValue("@number", 1)
  cmd.Parameters.AddWithValue("@text", "One")
  For i = 1 To 1000
    cmd.Parameters("@number").Value = i
    cmd.Parameters("@text").Value = "A string value"
    cmd.ExecuteNonQuery()
  Next
Catch ex As MySqlException
  MessageBox.Show("Error " & ex.Number & " has occurred: " & ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try

Пример на C#

MySql.Data.MySqlClient.MySqlConnection conn;
MySql.Data.MySqlClient.MySqlCommand cmd;

conn = new MySql.Data.MySqlClient.MySqlConnection();
cmd = new MySql.Data.MySqlClient.MySqlCommand();
conn.ConnectionString = strConnection;

try
{
  conn.Open();
  cmd.Connection = conn;
  cmd.CommandText = "INSERT INTO myTable VALUES(NULL, @number, @text)";
  cmd.Prepare();
  cmd.Parameters.AddWithValue("@number", 1);
  cmd.Parameters.AddWithValue("@text", "One");
  for (int i=1; i <= 1000; i++)
  {
    cmd.Parameters["@number"].Value = i;
    cmd.Parameters["@text"].Value = "A string value";
    cmd.ExecuteNonQuery();
  }
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
  MessageBox.Show("Error " + ex.Number + " has occurred: " + ex.Message,
                  "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

5.6. Доступ к хранимым процедурам в Connector/NET

MySQL 5.0 и выше поддерживает хранимые процедуры с синтаксисом хранимой процедуры SQL 2003.

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

Хранимые процедуры могут быть особенно полезными в ситуациях, таких как следующие:

  • Хранимые процедуры могут действовать как API или уровень абстракции, позволяя многочисленным клиентским приложениям выполнить те же самые операции по базе данных. Запросы могут быть написаны на различных языках и работать на различных платформах. Для приложений не нужно кодировать имена таблиц и столбцов, сложные запросы и так далее. Когда вы расширяете и оптимизируете запросы в хранимой процедуре, все приложения, которые вызывают процедуру, автоматически получают преимущества.

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

Connector/NET поддерживает поддерживает запрос хранимых процедур через объект MySqlCommand. Данные могут быть переданы в и из хранимой процедуры MySQL посредством использования коллекции MySqlCommand.Parameters.

Когда вы вызываете хранимую процедуру (в версиях до MySQL 8.0), объект команды делает дополнительный вызов SELECT, чтобы определить параметры хранимой процедуры. Необходимо гарантировать, что пользователь, вызывающий процедуру, имеет право SELECT на таблице mysql.proc, чтобы позволить проверить параметры. Отказ сделать это приведет к ошибке, вызывая процедуру.

Эта секция не предоставит всестороннюю информацию о создании хранимых процедур. Для такой информации, пожалуйста, обратитесь к https://dev.mysql.com/doc/mysql/en/stored-routines.html.

Применение приложения, демонстрирующее, как использовать хранимые процедуры с Connector/NET можно найти в каталоге Samples вашей установки Connector/NET.

5.6.1. Использование сохраненных подпрограмм из Connector/NET

Хранимые процедуры в MySQL могут быть созданы, используя множество инструментов. Во-первых, хранимые процедуры могут быть созданы, используя клиент командной строки mysql. Во-вторых, хранимые процедуры могут быть созданы, используя MySQL Workbench. Наконец, хранимые процедуры могут быть созданы, используя метод ExecuteNonQuery объекта MySqlCommand.

В отличие от командной строки и клиентов GUI, вы не обязаны определять специальный разделитель, создавая хранимые процедуры в Connector/NET.

Чтобы вызвать хранимую процедуру, используя Connector/NET, вы создаете объект MySqlCommand object и передаете имя хранимой процедуры как свойство CommandText. Вы тогда устанавливаете CommandType = CommandType.StoredProcedure.

После того, как хранимую процедуру вызывают, вы создаете по одному параметру MySqlCommand для каждого параметра в хранимой процедуре. Параметры IN определяются с названием параметра и объектом, содержащим значение. Параметры OUT определяются с названием параметра и типом данных, который, как ожидают, будет возвращен. Всем параметрам нужно определенное направление параметра.

После определения параметров вы вызываете хранимую процедуру при помощи метода MySqlCommand.ExecuteNonQuery().

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

Когда хранимую процедуру вызывают, используя MySqlCommand.ExecuteReader и хранимая процедура произвела параметры, вывод устанавливаются только после того, как MySqlDataReader, возвращенный ExecuteReader, будет закрыт.

Следующий пример кода C# демонстрирует использование хранимых процедур. Это предполагает, что база данных 'employees' уже была создана:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using MySql.Data;
using MySql.Data.MySqlClient;

namespace UsingStoredRoutines
{
  class Program
  {
    static void Main(string[] args)
    {
      MySqlConnection conn = new MySqlConnection();
      conn.ConnectionString = "server=localhost;user=root;database=employees;port=3306;password=******";
      MySqlCommand cmd = new MySqlCommand();
      try
      {
        Console.WriteLine("Connecting to MySQL...");
        conn.Open();
        cmd.Connection = conn;
        cmd.CommandText = "DROP PROCEDURE IF EXISTS add_emp";
        cmd.ExecuteNonQuery();
        cmd.CommandText = "DROP TABLE IF EXISTS emp";
        cmd.ExecuteNonQuery();
        cmd.CommandText = "CREATE TABLE emp (empno INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, first_name VARCHAR(20), last_name VARCHAR(20), birthdate DATE)";
        cmd.ExecuteNonQuery();
        cmd.CommandText = "CREATE PROCEDURE add_emp(" +
                          "IN fname VARCHAR(20), IN lname VARCHAR(20), IN bday DATETIME, OUT empno INT)" +
                          "BEGIN INSERT INTO emp(first_name, last_name, birthdate) " +
                          "VALUES(fname, lname, DATE(bday)); SET empno = LAST_INSERT_ID(); END";
        cmd.ExecuteNonQuery();
      }
      catch (MySqlException ex)
      {
        Console.WriteLine ("Error " + ex.Number + " has occurred: " + ex.Message);
      }
      conn.Close();
      Console.WriteLine("Connection closed.");
      try
      {
        Console.WriteLine("Connecting to MySQL...");
        conn.Open();
        cmd.Connection = conn;
        cmd.CommandText = "add_emp";
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@lname", "Jones");
        cmd.Parameters["@lname"].Direction = ParameterDirection.Input;
        cmd.Parameters.AddWithValue("@fname", "Tom");
        cmd.Parameters["@fname"].Direction = ParameterDirection.Input;
        cmd.Parameters.AddWithValue("@bday", "1940-06-07");
        cmd.Parameters["@bday"].Direction = ParameterDirection.Input;
        cmd.Parameters.Add("@empno", MySqlDbType.Int32);
        cmd.Parameters["@empno"].Direction = ParameterDirection.Output;
        cmd.ExecuteNonQuery();
        Console.WriteLine("Employee number: "+cmd.Parameters["@empno"].Value);
        Console.WriteLine("Birthday: " + cmd.Parameters["@bday"].Value);
      }
      catch (MySql.Data.MySqlClient.MySqlException ex)
      {
        Console.WriteLine("Error " + ex.Number + " has occurred: " + ex.Message);
      }
      conn.Close();
      Console.WriteLine("Done.");
    }
  }
}

Следующий код показывает то же самое в Visual Basic:

Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Data
Imports MySql.Data
Imports MySql.Data.MySqlClient

Module Module1
  Sub Main()
    Dim conn As New MySqlConnection()
    conn.ConnectionString = "server=localhost;user=root;database=world;port=3306;password=******"
    Dim cmd As New MySqlCommand()
    Try
      Console.WriteLine("Connecting to MySQL...")
      conn.Open()
      cmd.Connection = conn
      cmd.CommandText = "DROP PROCEDURE IF EXISTS add_emp"
      cmd.ExecuteNonQuery()
      cmd.CommandText = "DROP TABLE IF EXISTS emp"
      cmd.ExecuteNonQuery()
      cmd.CommandText = "CREATE TABLE emp (empno INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, first_name VARCHAR(20), last_name VARCHAR(20), birthdate DATE)"
      cmd.ExecuteNonQuery()
      cmd.CommandText = "CREATE PROCEDURE add_emp(" & "IN fname VARCHAR(20), IN lname VARCHAR(20), IN bday DATETIME, OUT empno INT)" & "BEGIN INSERT INTO emp(first_name, last_name, birthdate) " & "VALUES(fname, lname, DATE(bday)); SET empno = LAST_INSERT_ID(); END"
      cmd.ExecuteNonQuery()
    Catch ex As MySqlException
      Console.WriteLine(("Error " & ex.Number & " has occurred: ") + ex.Message)
    End Try
    conn.Close()
    Console.WriteLine("Connection closed.")
    Try
      Console.WriteLine("Connecting to MySQL...")
      conn.Open()
      cmd.Connection = conn
      cmd.CommandText = "add_emp"
      cmd.CommandType = CommandType.StoredProcedure
      cmd.Parameters.AddWithValue("@lname", "Jones")
      cmd.Parameters("@lname").Direction = ParameterDirection.Input
      cmd.Parameters.AddWithValue("@fname", "Tom")
      cmd.Parameters("@fname").Direction = ParameterDirection.Input
      cmd.Parameters.AddWithValue("@bday", "1940-06-07")
      cmd.Parameters("@bday").Direction = ParameterDirection.Input
      cmd.Parameters.Add("@empno", MySqlDbType.Int32)
      cmd.Parameters("@empno").Direction = ParameterDirection.Output
      cmd.ExecuteNonQuery()
      Console.WriteLine("Employee number: " & cmd.Parameters("@empno").Value)
      Console.WriteLine("Birthday: " & cmd.Parameters("@bday").Value)
    Catch ex As MySql.Data.MySqlClient.MySqlException
      Console.WriteLine(("Error " & ex.Number & " has occurred: ") + ex.Message)
    End Try
    conn.Close()
    Console.WriteLine("Done.")
  End Sub
End Module

5.7. Обработка данных BLOB с Connector/NET

Одно общее использование для MySQL это хранение двоичных данных в столбцах BLOB. MySQL поддерживает четыре различных типа данных BLOB: TINYBLOB, BLOB, MEDIUMBLOB и LONGBLOB, все описаны в The BLOB and TEXT Types и Data Type Storage Requirements.

К столбцу BLOB можно получить доступ, используя MySQL Connector/NET и управлять данными, используя клиентский код. Нет никаких особых требований для использования Connector/NET с данными BLOB.

Простые примеры кода будут представлены в этом разделе, и полное применение приложения может быть найдено в каталоге Samples Connector/NET.

5.7.1. Подготовка MySQL Server

Первый шаг использования MySQL с данными BLOB должен формировать сервер. Давайте начнем, составляя таблицу, к которой получат доступ. В моих таблицах файлов у меня обычно есть четыре колонки: AUTO_INCREMENT соответствующего размера (UNSIGNED SMALLINT), чтобы определить файл и служить первичным ключом, VARCHAR, которая хранит имя файла, UNSIGNED MEDIUMINT, которая хранит размер файла и MEDIUMBLOB, которая хранит сам файл. Для этого примера будем использовать определение следующей таблицы:

CREATE TABLE file(file_id SMALLINT UNSIGNED AUTO_INCREMENT
                  NOT NULL PRIMARY KEY,
                  file_name VARCHAR(64) NOT NULL,
                  file_size MEDIUMINT UNSIGNED NOT NULL,
                  file MEDIUMBLOB NOT NULL);

После составления таблицы вы, возможно, должны были бы изменить системную переменную max_allowed_packet. Эта переменная определяет, насколько большой пакет (то есть, единственная строка) может быть послан в сервер MySQL. По умолчанию сервер принимает только максимальный размер 1 МБ из клиентского приложения. Если вы намереваетесь превысить 1 МБ в своих передачах файлов, увеличьте это число.

Опция max_allowed_packet может быть изменена, используя MySQL Workbench Server Administration. Приспособьте опцию Maximum permitted в секции Data/Memory size вкладки Networking к соответствующему значению. После наладки значения нажмите кнопку Apply и перезапустите сервер, используя Startup/Shutdown в MySQL Workbench. Можно также приспособить это значение непосредственно в файле my.cnf (добавьте строку max_allowed_packet=xx M) или с использованием команды SET max_allowed_packet=xx M; в MySQL.

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

5.7.2. Запись файла в базу данных

Чтобы записать файл в базу данных, мы должны преобразовать файл в массив байтов, затем использовать массив байтов в качестве параметра для запроса INSERT.

Следующий код открывает файл, используя объект FileStream, читает его в массив байтов и вставляет уже этот массив в таблицу file:

Пример Visual Basic

Dim conn As New MySqlConnection
Dim cmd As New MySqlCommand
Dim SQL As String
Dim FileSize As UInt32
Dim rawData() As Byte
Dim fs As FileStream

conn.ConnectionString = "server=127.0.0.1;" _
                        & "uid=root;" _
                        & "pwd=12345;" _
                        & "database=test"

Try
  fs = New FileStream("c:\image.png", FileMode.Open, FileAccess.Read)
  FileSize = fs.Length
  rawData = New Byte(FileSize) {}
  fs.Read(rawData, 0, FileSize)
  fs.Close()
  conn.Open()
  SQL = "INSERT INTO file VALUES(NULL, @FileName, @FileSize, @File)"
  cmd.Connection = conn
  cmd.CommandText = SQL
  cmd.Parameters.AddWithValue("@FileName", strFileName)
  cmd.Parameters.AddWithValue("@FileSize", FileSize)
  cmd.Parameters.AddWithValue("@File", rawData)
  cmd.ExecuteNonQuery()
  MessageBox.Show("File Inserted into database successfully!", _
                  "Success!", MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
  conn.Close()
Catch ex As Exception
  MessageBox.Show("There was an error: " & ex.Message, "Error", _
  MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try

Пример на C#

MySql.Data.MySqlClient.MySqlConnection conn;
MySql.Data.MySqlClient.MySqlCommand cmd;
conn = new MySql.Data.MySqlClient.MySqlConnection();
cmd = new MySql.Data.MySqlClient.MySqlCommand();

string SQL;
UInt32 FileSize;
byte[] rawData;
FileStream fs;

conn.ConnectionString = "server=127.0.0.1;uid=root;" +
                        "pwd=12345;database=test";
try
{
  fs = new FileStream(@"c:\image.png", FileMode.Open, FileAccess.Read);
  FileSize = fs.Length;
  rawData = new byte[FileSize];
  fs.Read(rawData, 0, FileSize);
  fs.Close();
  conn.Open();
  SQL = "INSERT INTO file VALUES(NULL, @FileName, @FileSize, @File)";
  cmd.Connection = conn;
  cmd.CommandText = SQL;
  cmd.Parameters.AddWithValue("@FileName", strFileName);
  cmd.Parameters.AddWithValue("@FileSize", FileSize);
  cmd.Parameters.AddWithValue("@File", rawData);
  cmd.ExecuteNonQuery();
  MessageBox.Show("File Inserted into database successfully!",
                  "Success!", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
  conn.Close();
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
  MessageBox.Show("Error " + ex.Number + " has occurred: " + ex.Message,
                  "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

Метод Read объекта FileStream используется, чтобы загрузить файл в массив байтов, который измерен согласно свойству Length объекта FileStream.

После назначения массива байтов как параметра объекта MySqlCommand, вызывают метод ExecuteNonQuery и BLOB вставляется в таблицу file.

5.7.3. Чтение BLOB из базы данных в файл на диске

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

Следующий код восстанавливает строку из таблицы file, затем загружает данные в объект FileStream, который будет записан на диск:

Пример Visual Basic

Dim conn As New MySqlConnection
Dim cmd As New MySqlCommand
Dim myData As MySqlDataReader
Dim SQL As String
Dim rawData() As Byte
Dim FileSize As UInt32
Dim fs As FileStream

conn.ConnectionString = "server=127.0.0.1;" _
                        & "uid=root;" _
                        & "pwd=12345;" _
                        & "database=test"
SQL = "SELECT file_name, file_size, file FROM file"
Try
  conn.Open()
  cmd.Connection = conn
  cmd.CommandText = SQL
  myData = cmd.ExecuteReader
  If Not myData.HasRows Then Throw New Exception("There are no BLOBs to save")
  myData.Read()
  FileSize = myData.GetUInt32(myData.GetOrdinal("file_size"))
  rawData = New Byte(FileSize) {}
  myData.GetBytes(myData.GetOrdinal("file"), 0, rawData, 0, FileSize)
  fs = New FileStream("C:\newfile.png", FileMode.OpenOrCreate, FileAccess.Write)
  fs.Write(rawData, 0, FileSize)
  fs.Close()
  MessageBox.Show("File successfully written to disk!", "Success!", MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
  myData.Close()
  conn.Close()
Catch ex As Exception
  MessageBox.Show("There was an error: " & ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try

Пример на C#

MySql.Data.MySqlClient.MySqlConnection conn;
MySql.Data.MySqlClient.MySqlCommand cmd;
MySql.Data.MySqlClient.MySqlDataReader myData;
conn = new MySql.Data.MySqlClient.MySqlConnection();
cmd = new MySql.Data.MySqlClient.MySqlCommand();

string SQL;
UInt32 FileSize;
byte[] rawData;
FileStream fs;

conn.ConnectionString = "server=127.0.0.1;uid=root;" +
                        "pwd=12345;database=test";
SQL = "SELECT file_name, file_size, file FROM file";
try
{
  conn.Open();
  cmd.Connection = conn;
  cmd.CommandText = SQL;
  myData = cmd.ExecuteReader();
  if (! myData.HasRows) throw new Exception("There are no BLOBs to save");
  myData.Read();
  FileSize = myData.GetUInt32(myData.GetOrdinal("file_size"));
  rawData = new byte[FileSize];
  myData.GetBytes(myData.GetOrdinal("file"), 0, rawData, 0, (int)FileSize);
  fs = new FileStream(@"C:\newfile.png", FileMode.OpenOrCreate, FileAccess.Write);
  fs.Write(rawData, 0, (int)FileSize);
  fs.Close();
  MessageBox.Show("File successfully written to disk!",
                  "Success!", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
  myData.Close();
  conn.Close();
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
  MessageBox.Show("Error " + ex.Number + " has occurred: " + ex.Message,
                  "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

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

Метод GetOrdinal класса MySqlDataReader может использоваться, чтобы определить индекс целого числа названной колонки. Использование метода GetOrdinal предотвращает ошибки, если порядок следования столбцов в запросе SELECT не тот.

5.8. Асинхронные методы

Task-based Asynchronous Pattern (TAP) это образец для асинхронной работы в .NET Framework. Это сделано на основе типов Task и Task<TResult> пространства имен System.Threading.Tasks, которые используются, чтобы представлять произвольные асинхронные операции.

Async-Await это новые ключевые слова, введенные, чтобы работать с TAP. Async modifier используется, чтобы определить, что метод, лямбда-выражение или анонимный метод асинхронные. Оператор Await применяется к задаче в асинхронном методе, чтобы приостановить выполнение метода, пока ожидаемая задача не заканчивается.

Требования

  • Async-Await требует .NET Framework 4.5 или выше.

  • TAP требует .NET Framework 4.0 или выше.

  • MySQL Connector/NET 6.9 или выше.

Методы

Следующие методы могут использоваться с TAP или Async-Await.

  • Пространство имен MySql.Data.Entity

    • Класс EFMySqlCommand

      • Task PrepareAsync()

      • Task PrepareAsync(CancellationToken)

  • Пространство имен MySql.Data

    • Класс MySqlBulkLoader

      • Task<int> LoadAsync()

      • Task<int> LoadAsync(CancellationToken

    • Класс MySqlConnection

      • Task<MySqlTransaction> BeginTransactionAsync()

      • Task<MySqlTransaction> BeginTransactionAsync(CancellationToken)

      • Task<MySqlTransaction> BeginTransactionAsync(IsolationLevel)

      • Task<MySqlTransaction> BeginTransactionAsync (IsolationLevel, CancellationToken)

      • Task ChangeDatabaseAsync(string)

      • Task ChangeDatabaseAsync(string, CancellationToken)

      • Task CloseAsync()

      • Task CloseAsync(CancellationToken)

      • Task ClearPoolAsync(MySqlConnection)

      • Task ClearPoolAsync(MySqlConnection, CancellationToken)

      • Task ClearAllPoolsAsync()

      • Task ClearAllPoolsAsync(CancellationToken)

      • Task<MySqlSchemaCollection> GetSchemaCollection(string, string[])

      • Task<MySqlSchemaCollection> GetSchemaCollection(string, string[], CancellationToken)

    • Класс MySqlDataAdapter

      • Task<int> FillAsync(DataSet)

      • Task<int> FillAsync(DataSet, CancellationToken)

      • Task<int> FillAsync(DataTable)

      • Task<int> FillAsync(DataTable, CancellationToken)

      • Task<int> FillAsync(DataSet, string)

      • Task<int> FillAsync(DataSet, string, CancellationToken)

      • Task<int> FillAsync(DataTable, IDataReader)

      • Task<int> FillAsync(DataTable, IDataReader, CancellationToken)

      • Task<int> FillAsync(DataTable, IDbCommand, CommandBehavior)

      • Task<int> FillAsync(DataTable, IDbCommand, CommandBehavior, CancellationToken)

      • Task<int> FillAsync(int, int, params DataTable[])

      • Task<int> FillAsync(int, int, params DataTable[], CancellationToken)

      • Task<int> FillAsync(DataSet, int, int, string)

      • Task<int> FillAsync(DataSet, int, int, string, CancellationToken)

      • Task<int> FillAsync(DataSet, string, IDataReader, int, int)

      • Task<int> FillAsync(DataSet, string, IDataReader, int, int, CancellationToken)

      • Task<int> FillAsync(DataTable[], int, int, IDbCommand, CommandBehavior)

      • Task<int> FillAsync(DataTable[], int, int, IDbCommand, CommandBehavior, CancellationToken)

      • Task<int> FillAsync(DataSet, int, int, string, IDbCommand, CommandBehavior)

      • Task<int> FillAsync(DataSet, int, int, string, IDbCommand, CommandBehavior, CancellationToken)

      • Task<DataTable[]> FillSchemaAsync(DataSet, SchemaType)

      • Task<DataTable[]> FillSchemaAsync(DataSet, SchemaType, CancellationToken)

      • Task<DataTable[]> FillSchemaAsync(DataSet, SchemaType, string)

      • Task<DataTable[]> FillSchemaAsync(DataSet, SchemaType, string, CancellationToken)

      • Task<DataTable[]> FillSchemaAsync(DataSet, SchemaType, string, IDataReader)

      • Task<DataTable[]> FillSchemaAsync(DataSet, SchemaType, string, IDataReader, CancellationToken)

      • Task<DataTable[]> FillSchemaAsync(DataSet, SchemaType, IDbCommand, string, CommandBehavior)

      • Task<DataTable[]> FillSchemaAsync(DataSet, SchemaType, IDbCommand, string, CommandBehavior, CancellationToken)

      • Task<DataTable> FillSchemaAsync(DataTable, SchemaType)

      • Task<DataTable> FillSchemaAsync(DataTable, SchemaType, CancellationToken)

      • Task<DataTable> FillSchemaAsync(DataTable, SchemaType, IDataReader)

      • Task<DataTable> FillSchemaAsync(DataTable, SchemaType, IDataReader, CancellationToken)

      • Task<DataTable> FillSchemaAsync(DataTable, SchemaType, IDbCommand, CommandBehavior)

      • Task<DataTable> FillSchemaAsync(DataTable, SchemaType, IDbCommand, CommandBehavior, CancellationToken)

      • Task<int> UpdateAsync(DataRow[])

      • Task<int> UpdateAsync(DataRow[], CancellationToken)

      • Task<int> UpdateAsync(DataSet)

      • Task<int> UpdateAsync(DataSet, CancellationToken)

      • Task<int> UpdateAsync(DataTable)

      • Task<int> UpdateAsync(DataTable, CancellationToken)

      • Task<int> UpdateAsync(DataRow[], DataTableMapping, CancellationToken)

      • Task<int> UpdateAsync(DataSet, string)

      • Task<int> UpdateAsync(DataSet, string, CancellationToken)

    • Класс MySqlHelper

      • Task<DataRow> ExecuteDataRowAsync(string, string, params MySqlParameter[])

      • Task<DataRow> ExecuteDataRowAsync(string, string, CancellationToken, params MySqlParameter[])

      • Task<int> ExecuteNonQueryAsync(MySqlConnection, string, params MySqlParameter[])

      • Task<int> ExecuteNonQueryAsync(MySqlConnection, string, CancellationToken, params MySqlParameter[])

      • Task<int> ExecuteNonQueryAsync(string, string, params MySqlParameter[])

      • Task<int> ExecuteNonQueryAsync(string, string, CancellationToken, params MySqlParameter[])

      • Task<DataSet> ExecuteDatasetAsync(string, string)

      • Task<DataSet> ExecuteDatasetAsync(string, string, CancellationToken)

      • Task<DataSet> ExecuteDatasetAsync(string, string, CancellationToken, params MySqlParameter[])

      • Task<DataSet> ExecuteDatasetAsync(MySqlConnection, string)

      • Task<DataSet> ExecuteDatasetAsync(MySqlConnection, string, CancellationToken)

      • Task<DataSet> ExecuteDatasetAsync(MySqlConnection, string, params MySqlParameter[])

      • Task<DataSet> ExecuteDatasetAsync(MySqlConnection, string, CancellationToken, params MySqlParameter[])

      • Task UpdateDataSetAsync(string, string, DataSet, string)

      • Task UpdateDataSetAsync(string, string, DataSet, string, CancellationToken)

      • Task<MySqlDataReader> ExecuteReaderAsync(MySqlConnection, MySqlTransaction, string, MySqlParameter[], bool)

      • Task<MySqlDataReader> ExecuteReaderAsync(MySqlConnection, MySqlTransaction, string, MySqlParameter[], bool, CancellationToken)

      • Task<MySqlDataReader> ExecuteReaderAsync(string, string)

      • Task<MySqlDataReader> ExecuteReaderAsync(string, string, CancellationToken)

      • Task<MySqlDataReader> ExecuteReaderAsync(MySqlConnection, string)

      • Task<MySqlDataReader> ExecuteReaderAsync(MySqlConnection, string, CancellationToken)

      • Task<MySqlDataReader> ExecuteReaderAsync(string, string, params MySqlParameter[])

      • Task<MySqlDataReader> ExecuteReaderAsync(string, string, CancellationToken, params MySqlParameter[])

      • Task<MySqlDataReader> ExecuteReaderAsync(MySqlConnection, string, params MySqlParameter[])

      • Task<MySqlDataReader> ExecuteReaderAsync(MySqlConnection, string, CancellationToken, params MySqlParameter[])

      • Task<object> ExecuteScalarAsync(string, string)

      • Task<object> ExecuteScalarAsync(string, string, CancellationToken)

      • Task<object> ExecuteScalarAsync(string, string, params MySqlParameter[])

      • Task<object> ExecuteScalarAsync(string, string, CancellationToken, params MySqlParameter[])

      • Task<object> ExecuteScalarAsync(MySqlConnection, string)

      • Task<object> ExecuteScalarAsync(MySqlConnection, string, CancellationToken)

      • Task<object> ExecuteScalarAsync(MySqlConnection, string, params MySqlParameter[])

      • Task<object> ExecuteScalarAsync(MySqlConnection, string, CancellationToken, params MySqlParameter[])

    • Класс MySqlScript

      • Task<int> ExecuteAsync()

      • Task<int> ExecuteAsync(CancellationToken)

В дополнение к упомянутым выше методам следующее это методы, унаследованные от .NET Framework:

  • Пространство имен MySql.Data.Entity

    • Класс EFMySqlCommand

      • Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBehaviour, CancellationToken)

      • Task<int> ExecuteNonQueryAsync()

      • Task<int> ExecuteNonQueryAsync(CancellationToken)

      • Task<DbDataReader> ExecuteReaderAsync()

      • Task<DbDataReader> ExecuteReaderAsync(CancellationToken)

      • Task<DbDataReader> ExecuteReaderAsync(CommandBehaviour)

      • Task<DbDataReader> ExecuteReaderAsync(CommandBehaviour, CancellationToken)

      • Task<object> ExecuteScalarAsync()

      • Task<object> ExecuteScalarAsync(CancellationToken)

  • Пространство имен MySql.Data

    • Класс MySqlCommand

      • Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBehaviour, CancellationToken)

      • Task<int> ExecuteNonQueryAsync()

      • Task<int> ExecuteNonQueryAsync(CancellationToken)

      • Task<DbDataReader> ExecuteReaderAsync()

      • Task<DbDataReader> ExecuteReaderAsync(CancellationToken)

      • Task<DbDataReader> ExecuteReaderAsync(CommandBehaviour)

      • Task<DbDataReader> ExecuteReaderAsync(CommandBehaviour, CancellationToken)

      • Task<object> ExecuteScalarAsync()

      • Task<object> ExecuteScalarAsync(CancellationToken)

    • Класс MySqlConnection

      • Task OpenAsync()

      • Task OpenAsync(CancellationToken)

    • Класс MySqlDataReader

      • Task<T> GetFieldValueAsync<T>(int)

      • Task<T> GetFieldValueAsync<T>(int, CancellationToken)

      • Task<bool> IsDBNullAsync(int)

      • Task<bool> IsDBNullAsync(int, CancellationToken)

      • Task<bool> NextResultAsync()

      • Task<bool> NextResultAsync(CancellationToken)

      • Task<bool> ReadAsync()

      • Task<bool> ReadAsync(CancellationToken)

Примеры

Следующие примеры демонстрируют, как использовать асинхронные методы:

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

public async Task BulkLoadAsync()
{
  MySqlConnection myConn = new MySqlConnection("MyConnectionString");
  MySqlBulkLoader loader = new MySqlBulkLoader(myConn);
  loader.TableName = "BulkLoadTest";
  loader.FileName= @"c:\MyPath\MyFile.txt";
  loader.Timeout = 0;
  var result = await loader.LoadAsync();
}

В этом примере метод "async void" используется с "await" для метода ExecuteNonQueryAsync, чтобы соответствовать событию onclick кнопки. Поэтому метод не возвращает Task.

private async void myButton_Click()
{
  MySqlConnection myConn = new MySqlConnection("MyConnectionString");
  MySqlCommand proc= new MySqlCommand("MyAsyncSpTest", myConn);
  proc.CommandType = CommandType.StoredProcedure;
  int result = await proc.ExecuteNonQueryAsync();
}

5.9. Использование классов-перехватчиков Connector/NET

Перехватчик это шаблон программного дизайна, который обеспечивает прозрачный способ расширить или изменить некоторый аспект программы, подобно пользовательскому выходу. Никакое перекомпилирование не требуется. С MySQL Connector/NET перехватчики включены и выключены, обновив строку подключения, чтобы относиться к различным наборам классов перехватчиков, которые вы экземплируете.

Классы и методы, представленные в этой секции, не относятся к приложениям Connector/NET, разработанным с .NET Core 1.1.

Connector/NET включает следующие классы-перехватчики:

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

    Класс BaseCommandInterceptor имеет эти методы, которые можно перекрыть:

    public virtual bool ExecuteScalar(string sql, ref object returnValue);
    public virtual bool ExecuteNonQuery(string sql, ref int returnValue);
    public virtual bool ExecuteReader(string sql, CommandBehavior behavior,
                                      ref MySqlDataReader returnValue);
    public virtual void Init(MySqlConnection connection);
    

    Если ваш перехватчик перекрывает один из методов Execute..., установите параметр вывода returnValue и верните true, если вы обращались с событием, или false, если вы не обращались с событием. Команда SQL обрабатывается обычно только, когда все перехватчики команды возвращают false.

    Связь, переданная методу Init это связь, которая присоединена к этому перехватчику.

  • BaseExceptionInterceptor позволяет вам выполнить дополнительные операции, когда программа сталкивается с исключением SQL. Механизм перехвата исключения смоделирован после модели Connector/J. Можно закодировать класс перехватчика и соединить его с существующей программой без перекомпилирования и перехватить исключения, когда они создаются. Можно изменить тип исключительной ситуации и произвольно приложить информацию к нему. Эта способность позволяет вам включить и отключить регистрацию и отладку кода без жесткого кодирования чего-либо в приложении. Эта техника относится к исключениям, поднятым на уровне SQL, но не к системе низшего уровня или ошибкам I/O.

    Вы разрабатываете перехватчик исключений, сначала создавая подкласс класса BaseExceptionInterceptor. Необходимо перекрыть метод InterceptException(). Можно также перекрыть метод Init(), чтобы сделать некоторую одноразовую инициализацию.

    У каждого перехватчика исключения есть 2 метода:

    public abstract Exception InterceptException(Exception exception,
                                                 MySqlConnection connection);
    public virtual void Init(MySqlConnection connection);
    

    Связь, переданная Init() это связь, которая присоединена к этому перехватчику.

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

Вот примеры использования FQN (полностью квалифицированного имени) в строке подключения:

MySqlConnection c1 = new MySqlConnection(@"server=localhost;pooling=false;
                     commandinterceptors=CommandApp.MyCommandInterceptor,CommandApp");
MySqlConnection c2 = new MySqlConnection(@"server=localhost;pooling=false;
                     exceptioninterceptors=ExceptionStackTraceTest.MyExceptionInterceptor,
                     ExceptionStackTraceTest");

В этом примере перехватчик команды вызывает CommandApp.MyCommandInterceptor и существует в сборке CommandApp. Перехватчик исключения вызывает ExceptionStackTraceTest.MyExceptionInterceptor и существует в сборке ExceptionStackTraceTest.

Чтобы сократить строку подключения, можно зарегистрировать перехватчики исключения в вашем файле app.config или web.config:

<configSections>
  <section name="MySQL"
    type="MySql.Data.MySqlClient.MySqlConfiguration,MySql.Data"/>
</configSections>
<MySQL>
  <CommandInterceptors>
    <add name="myC" type="CommandApp.MyCommandInterceptor,CommandApp" />
  </CommandInterceptors>
</MySQL>

<configSections>
  <section name="MySQL" type="MySql.Data.MySqlClient.MySqlConfiguration,
    MySql.Data"/>
</configSections>

<MySQL>
  <ExceptionInterceptors>
    <add name="myE" type="ExceptionStackTraceTest.MyExceptionInterceptor,
      ExceptionStackTraceTest" />
  </ExceptionInterceptors>
</MySQL>

После того, как вы сделали это, ваши строки подключения могут быть похожими на:

MySqlConnection c1 = new MySqlConnection(@"server=localhost;pooling=false;
                                         commandinterceptors=myC");
MySqlConnection c2 = new MySqlConnection(@"server=localhost;pooling=false;
                                         exceptioninterceptors=myE");

5.10. Обработка информации о дате и времени в Connector/NET

MySQL и языки .NET обращаются с информацией о дате и времени по-другому. MySQL позволяет даты, которые не могут быть представлены типом данных .NET, например, '0000-00-00 00:00:00'. Эти различия могут вызвать проблемы, если неправильно обработаны.

Следующие разделы демонстрируют, как правильно обращаться с информацией о дате и времени, используя MySQL Connector/NET.

5.10.1. Доли секунд

MySQL Connector/NET понимает функцию долей секунды в MySQL, где часть долей секунды временных значений сохранена в данных через SQL. Для обработки доли секунды в MySQL 5.6.4 и выше см. Fractional Seconds in Time Values.

Чтобы использовать более точные типы даты и времени, определите значение от 1 до 6, создавая столбец таблицы, например, TIME(3) или DATETIME(6), представляющий количество цифр точности после десятичной точки. Определение точности 0 пропускает дробную часть полностью. В вашем коде C# или Visual Basic, обратитесь к члену Millisecond, чтобы восстановить значение доли секунды из объекта MySqlDateTime, возвращенного функцией GetMySqlDateTime. Объект DateTime, возвращенный функцией GetDateTime, также содержит фракционное значение, но только первые 3 цифры.

Для связанных примеров кода посмотрите следующее сообщение в блоге: https://blogs.oracle.com/MySqlOnWindows/entry/milliseconds_value_support_on_datetime.

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

Различия в обработке даты могут вызвать проблемы для разработчиков, которые используют недействительные даты. Недействительные даты MySQL не могут быть загружены в объекты .NET DateTime, включая даты NULL.

Из-за этой проблемы объекты .NET DataSet не могут быть заполнены методом Fill класса MySqlDataAdapter так как недействительные даты точно вызовут исключение System.ArgumentOutOfRangeException.

5.10.3. Ограничение недействительных дат

Лучшее решение проблемы даты состоит в том, чтобы ограничить пользователей во вводе недействительных дат. Это может быть сделано на клиенте или на серверной стороне.

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

Пользователи MySQL 5.0.2 и выше могут использовать новый режим SQL traditional, чтобы ограничить недействительные значения даты. Для получения информации об использовании режима SQL traditional см. Server SQL Modes.

5.10.4. Обработка недействительных дат

Хотя сильно рекомендуется, чтобы вы избежали использования недействительных дат в рамках вашего приложения на .NET, возможно использовать недействительные даты посредством типа данных MySqlDateTime.

Тип MySqlDateTime поддерживает для типов данных те же самые значения даты, которые поддерживаются сервером MySQL. Поведение по умолчанию Connector/NET должно возвратить объект .NET DateTime для действительных значений даты и возвратить ошибку для недействительных дат. Это может быть изменено, чтобы заставить Connector/NET возвращать объекты MySqlDateTime для недействительных дат.

Чтобы настроить Connector/NET на возврат объекта MySqlDateTime для недействительных дат, добавьте следующую строку к вашей строке подключения:

Allow Zero Datetime=True

Класс MySqlDateTime может все еще быть проблематичным. Следующее это некоторые известные проблемы:

  • Привязка данных для недействительных дат может все еще вызвать ошибки (у нулевых дат как 0000-00-00, кажется, нет этой проблемы).

  • Метод ToString возвращает дату, отформатированную в стандартном формате MySQL (например, 2005-02-23 08:50:25). Это отличается от логики ToString класса .NET DateTime.

  • Класс MySqlDateTime понимает даты NULL, в то время как класс .NET DateTime этого не делает. Это может вызвать ошибки, пытаясь преобразовать MySQLDateTime в DateTime, если вы не проверяете на NULL сначала.

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

5.10.5. Обработка дат NULL

Тип .NET DateTime не может обращаться со значением NULL. По сути, назначая значения от запроса переменной DateTime, необходимо сначала проверить, является ли значение на самом деле NULL.

Используя MySqlDataReader, используйте метод .IsDBNull, чтобы проверить, является ли значение NULL прежде, чем сделать назначение:

Пример Visual Basic

If Not myReader.IsDBNull(myReader.GetOrdinal("mytime")) Then
   myTime = myReader.GetDateTime(myReader.GetOrdinal("mytime"))
Else
  myTime = DateTime.MinValue
End If

Пример на C#

if (! myReader.IsDBNull(myReader.GetOrdinal("mytime")))
   myTime = myReader.GetDateTime(myReader.GetOrdinal("mytime"));
else myTime = DateTime.MinValue;

Значения NULL будут работать в наборе данных и могут быть обязаны сформировать средства управления без специальной обработки.

5.11. Применение класса MySqlBulkLoader

MySQL Connector/NET показывает оптовый класс загрузчика, который обертывает запрос LOAD DATA INFILE. Это дает Connector/NET способность загрузить файл данных от местного или отдаленного сервера. Затронутый класс MySqlBulkLoader. У этого класса есть различные методы, главный это load, чтобы заставить указанный файл загрузиться на сервер. Различные параметры могут быть установлены, чтобы управлять, как именно файл данных обрабатывается. Это достигается посредством настройки различных свойств класса. Например, используемый разделитель полей, такой как запятая или табуляция, может быть определен, наряду с терминатором записей, таким как новая строка.

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

CREATE TABLE Career (Name VARCHAR(100) NOT NULL,
                     Age INTEGER,
                     Profession VARCHAR(200));

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

Table Career in Test Database
Name Age Profession

Tony 47 Technical Writer
Ana 43 Nurse
Fred 21 IT Specialist
Simon 45 Hairy Biker

Первые три строки должны быть проигнорированы с этим испытательным файлом, поскольку они не содержат данные о таблице. Это может быть достигнуто, используя свойство NumberOfLinesToSkip. Этот файл может загружаться и использоваться, чтобы заполнить таблицу Career базы данных test.

С Connector/NET 8.0.15 свойство Local должно быть установлено в True явно, чтобы позволить функциональность local-infile. Предыдущие версии устанавливают это значение в True по умолчанию.

using System;
using System.Text;
using MySql.Data;
using MySql.Data.MySqlClient;

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      string connStr = "server=localhost;user=root;database=test;port=3306;password=******";
      MySqlConnection conn = new MySqlConnection(connStr);
      MySqlBulkLoader bl = new MySqlBulkLoader(conn);
      bl.Local = true;
      bl.TableName = "Career";
      bl.FieldTerminator = "\t";
      bl.LineTerminator = "\n";
      bl.FileName = "c:/career_data.txt";
      bl.NumberOfLinesToSkip = 3;
      try
      {
        Console.WriteLine("Connecting to MySQL...");
        conn.Open();
        // Upload data from file
        int count = bl.Load();
        Console.WriteLine(count + " lines uploaded.");
        string sql = "SELECT Name, Age, Profession FROM Career";
        MySqlCommand cmd = new MySqlCommand(sql, conn);
        MySqlDataReader rdr = cmd.ExecuteReader();
        while (rdr.Read())
        {
          Console.WriteLine(rdr[0] + " -- " + rdr[1] + " -- " + rdr[2]);
        }
        rdr.Close();
        conn.Close();
      }
      catch (Exception ex)
      {
        Console.WriteLine(ex.ToString());
      }
      Console.WriteLine("Done.");
    }
  }
}

Дополнительная информация о LOAD DATA INFILE см. в LOAD DATA Statement.

5.12. Использование объекта Connector/NET Trace Source

Поисковая архитектура .NET 2.0 состоит из четырех главных частей:

  • Source создатель трассировочной информации. Источник используется, чтобы послать сообщения трассировки. Название источника, обеспеченного Connector/NET, mysql.

  • Switch определяет уровень трассировочной информации. Как правило, это определяется в файле app.config, чтобы не было необходимо повторно собрать приложение, чтобы изменить уровень трассировки.

  • Listener приемники трассировки определяют, где трассировочная информация будет написана. Поддержанные слушатели включают, например, консоль, окно Visual Studio Output или Windows Event Log.

  • Filter фильтры могут быть присоединены к слушателям. Фильтры определяют уровень трассировочной информации, которая будет написана. В то время как выключатель определяет уровень информации, которая будет вообще написана всем слушателям, фильтр может быть применен на основе слушателя, дав более точный контроль трассировочной информации.

Чтобы использовать отслеживание MySql.Data.MySqlClient.MySqlTrace может использоваться в качестве TraceSource для Connector/NET, строка подключения должна включать "Logging=True".

Чтобы позволить сообщения трассировки, формируйте переключатель трассировки. Переключатели трассировки имеют связанное с ними перечисление уровней трассировки, это: Off, Error, Warning, Info и Verbose.

MySqlTrace.Switch.Level = SourceLevels.Verbose;

Это устанавливает уровень трассировки в Verbose, означая, что все сообщения трассировки будут написаны.

Удобно быть в состоянии изменить уровень трассировки, не имея необходимости повторно собирать код. Это достигается, определяя уровень трассировки в файле конфигурации приложения app.config. Тогда просто необходимо определить желаемый уровень трассировки в конфигурационном файле и перезапустить применение. Источник трассировки формируется в секции system.diagnostics файла. Следующий отрывок XML иллюстрирует это:

<configuration>
  ...
  <system.diagnostics>
    <sources>
      <source name="mysql" switchName="MySwitch"
        switchType="System.Diagnostics.SourceSwitch" />
      ...
    </sources>
    <switches>
      <add name="MySwitch" value="Verbose"/>
      ...
    </switches>
  </system.diagnostics>
  ...
</configuration>

По умолчанию трассировочная информация написана в окно Output Microsoft Visual Studio. Есть широкий спектр слушателей, которые могут быть привязаны к источнику трассировки, чтобы сообщения трассировки могли быть написаны к различным местам назначения. Можно также создать своих слушателей, чтобы позволить сообщениям трассировки быть написанными к другим местам назначения, например, мобильным устройствам и веб-сервисам. Обычно используемый пример слушателя это ConsoleTraceListener, который пишет сообщения трассировки на консоль.

Чтобы добавить слушателя во время выполнения, используйте примерно такой код:

ts.Listeners.Add(new ConsoleTraceListener());

Затем вызовите методы на исходном объекте трассировки, чтобы произвести трассировочную информацию. Например, методы TraceInformation(), TraceEvent() или TraceData().

5.12.1. Просмотр трассировочной информации MySQL

Эта секция описывает, как настроить ваше приложение, чтобы рассмотреть трассировочную информацию MySQL.

Первая вещь, которую необходимо сделать, это создать подходящий файл app.config для вашего приложения. Например:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.diagnostics>
    <sources>
      <source name="mysql" switchName="SourceSwitch"
        switchType="System.Diagnostics.SourceSwitch" >
        <listeners>
          <add name="console" />
          <remove name ="Default" />
        </listeners>
      </source>
    </sources>

    <switches>
      <!-- You can set the level at which tracing is to occur -->
      <add name="SourceSwitch" value="Verbose" />
      <!-- You can turn tracing off -->
      <!--add name="SourceSwitch" value="Off" -->
    </switches>

    <sharedListeners>
      <add name="console" type="System.Diagnostics.ConsoleTraceListener"
        initializeData="false"/>
    </sharedListeners>
  </system.diagnostics>
</configuration>

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

Теперь добавьте logging=true к строке подключения в вашем приложении. Например:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using MySql.Data;
using MySql.Data.MySqlClient;
using MySql.Web;

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      string connStr = "server=localhost;user=root;database=world;port=3306;password=******;logging=true";
      MySqlConnection conn = new MySqlConnection(connStr);
      try
      {
        Console.WriteLine("Connecting to MySQL...");
        conn.Open();
        string sql = "SELECT Name, HeadOfState FROM Country WHERE Continent='Oceania'";
        MySqlCommand cmd = new MySqlCommand(sql, conn);
        MySqlDataReader rdr = cmd.ExecuteReader();
        while (rdr.Read())
        {
          Console.WriteLine(rdr[0] + " -- " + rdr[1]);
        }
        rdr.Close();
        conn.Close();
      }
      catch (Exception ex)
      {
        Console.WriteLine(ex.ToString());
      }
      Console.WriteLine("Done.");
    }
  }
}

Это простое приложение производит следующий вывод:

Connecting to MySQL...
mysql Information: 1 : 1: Connection Opened:
  connection string = 'server=localhost;User Id=root;database=world;port=3306
                       ;password=******;logging=True'
mysql Information: 3 : 1: Query Opened: SHOW VARIABLES
mysql Information: 4 : 1: Resultset Opened: field(s) = 2, affected rows = -1,
                          inserted id = -1
mysql Information: 5 : 1: Resultset Closed. Total rows=272, skipped rows=0,
                          size (bytes)=7058
mysql Information: 6 : 1: Query Closed
mysql Information: 3 : 1: Query Opened: SHOW COLLATION
mysql Information: 4 : 1: Resultset Opened: field(s) = 6, affected rows = -1,
                          inserted id = -1
mysql Information: 5 : 1: Resultset Closed. Total rows=127, skipped rows=0,
                          size (bytes)=4102
mysql Information: 6 : 1: Query Closed
mysql Information: 3 : 1: Query Opened: SET character_set_results=NULL
mysql Information: 4 : 1: Resultset Opened: field(s) = 0, affected rows = 0,
                          inserted id = 0
mysql Information: 5 : 1: Resultset Closed. Total rows=0, skipped rows=0,
                          size (bytes)=0
mysql Information: 6 : 1: Query Closed
mysql Information: 10 : 1: Set Database: world
mysql Information: 3 : 1: Query Opened: SELECT Name, HeadOfState
                          FROM Country WHERE Continent='Oceania'
mysql Information: 4 : 1: Resultset Opened: field(s) = 2, affected rows = -1,
                          inserted id = -1
American Samoa -- George W. Bush
Australia -- Elisabeth II
...
Wallis and Futuna -- Jacques Chirac
Vanuatu -- John Bani
United States Minor Outlying Islands -- George W. Bush
mysql Information: 5 : 1: Resultset Closed. Total rows=28, skipped rows=0,
                          size (bytes)=788
mysql Information: 6 : 1: Query Closed
Done.
mysql Information: 2 : 1: Connection Closed

Первое число, показанное в сообщении трассировки, соответствует типу события MySQL. Второе число, показанное в сообщении трассировки, является счетчиком связей. Следующая таблица описывает каждый тип события MySQL.

Тип событияОписание
1 ConnectionOpened: строка подключения.
2ConnectionClosed:
3QueryOpened: id потока сервера mysql, текст запроса.
4ResultOpened: полевое количество, затронутые строки (-1, если select), вставленный id (-1, если select).
5ResultClosed: всего прочитано строк, пропущено строк, размер набора результатов в байтах.
6QueryClosed:
7StatementPrepared: подготовленный sql, идентификатор запроса.
8StatementExecuted: идентификатор запроса, id потока mysql server.
9StatementClosed: идентификатор запроса.
10NonQuery: [varies]
11UsageAdvisorWarning: использованный флаг. NoIndex = 1, BadIndex = 2, SkippedRows = 3, SkippedColumns=4, FieldConversion=5.
12Warning: уровень, код, сообщение.
13Error: номер ошибки, сообщение.

Хотя этот пример использует ConsoleTraceListener, любой из других типичных слушателей может использоваться. Другая возможность состоит в том, чтобы создать своего слушателя, который использует информацию, переданную методом TraceEvent. Например, свой приемник трассировки может быть создан, чтобы выполнить активный контроль сообщений о событиях MySQL, вместо того, чтобы просто писать их устройству вывода.

Также возможно добавить слушателей в MySQL Trace Source во время выполнения. Это может быть сделано следующим кодом:

MySqlTrace.Listeners.Add(new ConsoleTraceListener());

Connector/NET обеспечивает способность включить и выключить отслеживание во время выполнения. Это может быть достигнуто, используя MySqlTrace.EnableQueryAnalyzer(string host, int postInterval) и MySqlTrace.DisableQueryAnalyzer(). Параметр host это URL сервера MySQL Enterprise Monitor. Параметр postInterval задает как часто отправить данные MySQL Enterprise Monitor в секундах.

5.12.2. Строя свои слушатели

Чтобы построить своих слушателей, которые работают с MySQL Connector/NET Trace Source, необходимо понять ключевые методы и используемые форматы данных о событии.

Основной метод прослеживает сообщения, это TraceSource.TraceEvent:

public void TraceEvent(TraceEventType eventType, int id, string format,
                       params Object[] args)

Этот метод трассировки обработает список приложенных слушателей и вызовет метод TraceListener.TraceEvent слушателя. Прототип для TraceListener.TraceEvent:

public virtual void TraceEvent(TraceEventCache eventCache, string source,
                               TraceEventType eventType, int id,
                               string format, params Object[] args)

Первые три параметра используются в стандарте, как определено Microsoft. Последние три параметра содержат MySQL-определенную трассировочную информацию. Каждый из этих параметров теперь будет обсужден более подробно.

int id

Это MySQL-определенный идентификатор. Это определяет тип события MySQL, которое произошло, приведя к сообщению трассировки. Это значение определяется MySqlTraceEventType public enum в коде Connector/NET:

public enum MySqlTraceEventType : int
{
  ConnectionOpened = 1, ConnectionClosed, QueryOpened, ResultOpened,
  ResultClosed, QueryClosed, StatementPrepared, StatementExecuted,
  StatementClosed, NonQuery, UsageAdvisorWarning, Warning, Error
}

Тип события MySQL также решает, что содержание передано с использованием параметра params Object[] args. Природа параметров args описана более подробно в следующем материале.

string format

Это строка формата, которая содержит ноль или больше элементов формата, которые соответствуют объектам в массиве args. Это использовалось бы таким слушателем, как ConsoleTraceListener, чтобы написать сообщение устройству вывода.

params Object[] args

Это список объектов, который зависит от типа события MySQL и id. Однако первый параметр, переданный с использованием этого списка, всегда является id драйвера. Это уникальное число, которое увеличено каждый раз, когда соединитель открыт. Это позволяет группам запросов на той же самой связи быть определенными. Параметры, которые следуют за id драйвера, зависят от id событий MySQL следующим образом:

Тип MySQL-определенного события Аргументы (params Object[] args)
ConnectionOpenedСтрока подключения.
ConnectionClosed Никакие дополнительные параметры не заданы.
QueryOpened id потока сервера mysql, текст запроса.
ResultOpened Счетчик полей, затронутые строки (-1, если select), вставленный id (-1, если select).
ResultClosed Всего прочитано строк, пропущено строк, размер набора результатов в байтах.
QueryClosed Никакие дополнительные параметры не заданы.
StatementPrepared Подготовленный sql, идентификатор запроса.
StatementExecuted Идентификатор запроса, id потока сервера mysql.
StatementClosedИдентификатор запроса.
NonQueryВарьируется.
UsageAdvisorWarning Флаг подсказки. NoIndex = 1, BadIndex = 2, SkippedRows = 3, SkippedColumns = 4, FieldConversion = 5.
WarningУровень, код, сообщение.
Error Код ошибки, сообщение об ошибке.

Эта информация позволит вам создавать свои приемники трассировки, которые могут активно контролировать MySQL-определенные события.

5.13. Двоичные и недвоичные проблемы

Есть определенные ситуации, куда MySQL возвратит неправильные метаданные об одной или более колонках. Более определенно сервер может иногда сообщать, что колонка двоичная, когда это не так (и наоборот). В этих ситуациях для соединителя становится практически невозможно правильно определить истинные метаданные.

Некоторые примеры ситуаций, которые могут возвратить неправильные метаданные:

  • Выполнение SHOW PROCESSLIST. Некоторые колонки возвращены как двоичные даже при том, что они содержат только строковые данные.

  • Когда временная таблица используется, чтобы обработать набор результатов, некоторые колонки могут быть возвращены с неправильными двоичными флагами.

  • Некоторый серверные функции вроде DATE_FORMAT могут возвратить колонку неправильно как двоичную.

С типами данных BINARY и VARBINARY важно уважать метаданные, возвращенные сервером. Однако, некоторые существующие приложения могут столкнуться с проблемами с этим изменением и могут использовать опцию строки подключения, чтобы включить или отключить его. По умолчанию Connector/NET уважает двоичные флаги, возвращенные сервером. Вы, возможно, должны были бы внести небольшие изменения в свое приложение, чтобы обработать это изменение.

Если изменения, требуемые вашему запросу, слишком большие, добавление 'respect binary flags=false' к вашей строке подключения заставляет соединитель использовать такое поведение: любая колонка, которая отмечена как последовательность, независимо от двоичных флагов, будет возвращена как последовательность. Только колонки, которые определенно отмечены как BLOB, будут возвращены именно как BLOB.

5.14. Соображения о наборе символов для Connector/NET

Рассмотрение двоичных объектов как UTF8

До того, как сделали 4-байтового набора символов UTF-8 MySQL не поддерживал 4-байтовые последовательности UTF8. Это мешало представлять некоторые мультибайтные языки, такие как японский язык. Чтобы попытаться облегчить это, MySQL Connector/NET поддерживает способ, где двоичные объекты можно рассматривать как последовательности.

Чтобы сделать это, вы устанавливаете ключевое слово строки подключения 'Treat Blobs As UTF8' = true. Это все, что должно быть сделано, чтобы позволить преобразование всех двоичных объектов к последовательностям UTF8. Чтобы преобразовать только некоторые ваши колонки BLOB, можно использовать ключевые слова 'BlobAsUTF8IncludePattern' и 'BlobAsUTF8ExcludePattern'. Установите их в образец регулярного выражения, который соответствует именам столбцов, чтобы включать или исключить соответственно.

Когда образцы регулярного выражения оба соответствуют отдельному столбцу, образец включения применяется перед образцом исключения. Результат в этом случае состоит в том, что колонка исключена. Кроме того, знайте, что этот способ не относится к колонкам типа BINARY или VARBINARY, а также не обращайтесь к недвоичным столбцам BLOB.

Этот способ относится только к чтению строк из MySQL. Чтобы вставить 4-байтовые последовательности UTF8 в колонки blob, используйте функцию .NET Encoding.GetBytes, чтобы преобразовать вашу последовательность в ряд байтов. Можно установить этот массив байтов в качестве параметра для столбца BLOB.

5.15. Connector/NET и Crystal Reports

Crystal Reports это общий инструмент, используемый разработчиками приложений Windows, чтобы выполнить генерацию документов. В этой секции мы покажем, как использовать Crystal Reports XI с MySQL и MySQL Connector/NET.

5.15.1. Создание источника данных

Создавая отчет в Crystal Reports есть две возможности для доступа к данным MySQL.

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

Второй вариант состоит в том, чтобы создать набор данных в VB.NET и сохранить его как XML. Этот XML-файл может использоваться, чтобы проектировать отчет. Это работает хорошо, показывая отчет в вашем приложении, но менее универсально во время проектирования, потому что необходимо выбрать все соответствующие колонки, создавая набор данных. Если вы забываете колонку, необходимо воссоздать набор данных, прежде чем колонка сможет быть добавлена к отчету.

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

Пример Visual Basic

Dim myData As New DataSet
Dim conn As New MySqlConnection
Dim cmd As New MySqlCommand
Dim myAdapter As New MySqlDataAdapter

conn.ConnectionString = "server=127.0.0.1;" _
                        & "uid=root;" _
                        & "pwd=12345;" _
                        & "database=world"
Try
  conn.Open()
  cmd.CommandText = "SELECT city.name AS cityName, city.population AS CityPopulation, " _
                    & "country.name, country.population, country.continent " _
                    & "FROM country, city ORDER BY country.continent, country.name"
  cmd.Connection = conn
  myAdapter.SelectCommand = cmd
  myAdapter.Fill(myData)
  myData.WriteXml("C:\dataset.xml", XmlWriteMode.WriteSchema)
Catch ex As Exception
  MessageBox.Show(ex.Message, "Report could not be created", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try

Пример на C#

DataSet myData = new DataSet();
MySql.Data.MySqlClient.MySqlConnection conn;
MySql.Data.MySqlClient.MySqlCommand cmd;
MySql.Data.MySqlClient.MySqlDataAdapter myAdapter;

conn = new MySql.Data.MySqlClient.MySqlConnection();
cmd = new MySql.Data.MySqlClient.MySqlCommand();
myAdapter = new MySql.Data.MySqlClient.MySqlDataAdapter();

conn.ConnectionString = "server=127.0.0.1;uid=root;" +
                        "pwd=12345;database=test";
try
{
  cmd.CommandText = "SELECT city.name AS cityName, city.population AS CityPopulation, " +
                    "country.name, country.population, country.continent " +
                    "FROM country, city ORDER BY country.continent, country.name";
  cmd.Connection = conn;
  myAdapter.SelectCommand = cmd;
  myAdapter.Fill(myData);
  myData.WriteXml(@"C:\dataset.xml", XmlWriteMode.WriteSchema);
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
  MessageBox.Show(ex.Message, "Report could not be created",
  MessageBoxButtons.OK, MessageBoxIcon.Error);
}

Получающийся XML-файл может использоваться в качестве источника данных ADO.NET XML, проектируя ваш отчет.

Если вы принимаете решение проектировать свои отчеты, используя Connector/ODBC, он может быть загружен с dev.mysql.com.

5.15.2. Создание записи

В большинстве целей мастер Standard Report помогает с начальным созданием записи. Чтобы начать работу с мастером, откройте Crystal Reports и выберите из меню File New > Standard Report.

Мастер сначала спросит вас об источнике данных. При использовании Connector/ODBC в качестве своего источника данных, используйте провайдера OLE DB для опции ODBC из дерева OLE DB (ADO) вместо дерева ODBC (RDO), выбирая источник данных. Используя сохраненный набор данных, выберите ADO.NET (XML) и перейдите к своему набору данных.

Остаток процесса создания записи сделан автоматически мастером.

После того, как отчет создается, выберите пункт Report Options из меню File. Снимите флажок Save Data With Report. Это препятствует тому, чтобы сохраненные данные вмешались в загрузку данных в рамках нашего приложения.

5.15.3. Показ записи

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

Следующие ссылки необходимы в проекте, который показывает отчет:

  • CrystalDecisions.CrystalReports.Engine

  • CrystalDecisions.ReportSource

  • CrystalDecisions.Shared

  • CrystalDecisions.Windows.Forms

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

Пример Visual Basic

Imports CrystalDecisions.CrystalReports.Engine
Imports System.Data
Imports MySql.Data.MySqlClient

Dim myReport As New ReportDocument
Dim myData As New DataSet
Dim conn As New MySqlConnection
Dim cmd As New MySqlCommand
Dim myAdapter As New MySqlDataAdapter

conn.ConnectionString = _"server=127.0.0.1;" _
                        & "uid=root;" _
                        & "pwd=12345;" _
                        & "database=test"
Try
  conn.Open()
  cmd.CommandText = "SELECT city.name AS cityName, city.population AS CityPopulation, " _
                    & "country.name, country.population, country.continent " _
                    & "FROM country, city ORDER BY country.continent, country.name"
  cmd.Connection = conn
  myAdapter.SelectCommand = cmd
  myAdapter.Fill(myData)
  myReport.Load(".\world_report.rpt")
  myReport.SetDataSource(myData)
  myViewer.ReportSource = myReport
Catch ex As Exception
  MessageBox.Show(ex.Message, "Report could not be created", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try

Пример на C#

using CrystalDecisions.CrystalReports.Engine;
using System.Data;
using MySql.Data.MySqlClient;

ReportDocument myReport = new ReportDocument();
DataSet myData = new DataSet();
MySql.Data.MySqlClient.MySqlConnection conn;
MySql.Data.MySqlClient.MySqlCommand cmd;
MySql.Data.MySqlClient.MySqlDataAdapter myAdapter;

conn = new MySql.Data.MySqlClient.MySqlConnection();
cmd = new MySql.Data.MySqlClient.MySqlCommand();
myAdapter = new MySql.Data.MySqlClient.MySqlDataAdapter();
conn.ConnectionString = "server=127.0.0.1;uid=root;" +
                        "pwd=12345;database=test";
try
{
  cmd.CommandText = "SELECT city.name AS cityName, city.population AS CityPopulation, " +
                    "country.name, country.population, country.continent " +
                    "FROM country, city ORDER BY country.continent, country.name";
  cmd.Connection = conn;
  myAdapter.SelectCommand = cmd;
  myAdapter.Fill(myData);
  myReport.Load(@".\world_report.rpt");
  myReport.SetDataSource(myData);
  myViewer.ReportSource = myReport;
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
  MessageBox.Show(ex.Message, "Report could not be created",
  MessageBoxButtons.OK, MessageBoxIcon.Error);
}

Новый набор данных произведен с использованием того же самого запроса, который производил ранее сохраненный набор данных. Как только набор данных заполнен, ReportDocument используется, чтобы загрузить файл записи и связать его с набором данных. ReportDocument передан как ReportSource в crViewer.

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

Когда отчет создается из многих таблиц, используя Connector/ODBC, набор данных с многими таблицами должен быть создан в нашем приложении. Это позволяет каждой таблице в источнике данных отчетов быть замененной отчетом в наборе данных.

Мы наполняем набор данных с многими таблицами, обеспечивая много операторов SELECT в нашем объекте MySqlCommand. Эти SELECT основаны на SQL-запросе, показанном в Crystal Reports в меню Database, элемент Show SQL Query. Примите следующий запрос:

SELECT `country`.`Name`, `country`.`Continent`, `country`.`Population`,
       `city`.`Name`, `city`.`Population`
       FROM `world`.`country` `country` LEFT OUTER JOIN `world`.`city` `city`
       ON `country`.`Code`=`city`.`CountryCode`
       ORDER BY `country`.`Continent`, `country`.`Name`, `city`.`Name`

Этот запрос преобразовывается в два запроса SELECT и показан следующим кодом:

Пример Visual Basic

Imports CrystalDecisions.CrystalReports.Engine
Imports System.Data
Imports MySql.Data.MySqlClient

Dim myReport As New ReportDocument
Dim myData As New DataSet
Dim conn As New MySqlConnection
Dim cmd As New MySqlCommand
Dim myAdapter As New MySqlDataAdapter

conn.ConnectionString = "server=127.0.0.1;" _
                        & "uid=root;" _
                        & "pwd=12345;" _
                        & "database=world"
Try
  conn.Open()
  cmd.CommandText = "SELECT name, population, countrycode FROM city ORDER BY countrycode, name; " _
                    & "SELECT name, population, code, continent FROM country ORDER BY continent, name"
  cmd.Connection = conn
  myAdapter.SelectCommand = cmd
  myAdapter.Fill(myData)
  myReport.Load(".\world_report.rpt")
  myReport.Database.Tables(0).SetDataSource(myData.Tables(0))
  myReport.Database.Tables(1).SetDataSource(myData.Tables(1))
  myViewer.ReportSource = myReport
Catch ex As Exception
  MessageBox.Show(ex.Message, "Report could not be created", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try

Пример на C#

using CrystalDecisions.CrystalReports.Engine;
using System.Data;
using MySql.Data.MySqlClient;

ReportDocument myReport = new ReportDocument();
DataSet myData = new DataSet();
MySql.Data.MySqlClient.MySqlConnection conn;
MySql.Data.MySqlClient.MySqlCommand cmd;
MySql.Data.MySqlClient.MySqlDataAdapter myAdapter;

conn = new MySql.Data.MySqlClient.MySqlConnection();
cmd = new MySql.Data.MySqlClient.MySqlCommand();
myAdapter = new MySql.Data.MySqlClient.MySqlDataAdapter();

conn.ConnectionString = "server=127.0.0.1;uid=root;" +
                        "pwd=12345;database=test";
try
{
  cmd.CommandText = "SELECT name, population, countrycode FROM city ORDER " +
                    "BY countrycode, name; SELECT name, population, code, continent FROM " +
                    "country ORDER BY continent, name";
  cmd.Connection = conn;
  myAdapter.SelectCommand = cmd;
  myAdapter.Fill(myData);
  myReport.Load(@".\world_report.rpt");
  myReport.Database.Tables(0).SetDataSource(myData.Tables(0));
  myReport.Database.Tables(1).SetDataSource(myData.Tables(1));
  myViewer.ReportSource = myReport;
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
  MessageBox.Show(ex.Message, "Report could not be created",
  MessageBoxButtons.OK, MessageBoxIcon.Error);
}

Важно выполнить запросы SELECT в алфавитном порядке, поскольку отчет будет ожидать, что его исходные таблицы будут в этом порядке. Один вызов SetDataSource необходим для каждой таблицы в записи.

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

5.16. Модель провайдера ASP.NET

MySQL Connector/NET включает модель провайдера для использования с ASP.NET. Эта модель позволяет разработчикам приложений сосредоточиться на бизнес-логике их приложения вместо того, чтобы воссоздавать такие шаблонные пункты как ролевая поддержка и членство.

Connector/NET предлагает следующих веб-провайдеров:

  • Membership

  • Roles

  • Profiles

  • Session state

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

Membership

Провайдер по умолчаниюПровайдер MySQL
System.Web.Security.SqlMembershipProvider MySql.Web.Security.MySQLMembershipProvider

Role

Провайдер по умолчаниюПровайдер MySQL
System.Web.Security.SqlRoleProvider MySql.Web.Security.MySQLRoleProvider

Profile

Провайдер по умолчаниюПровайдер MySQL
System.Web.Profile.SqlProfileProvider MySql.Web.Profile.MySQLProfileProvider

Session State

Провайдер по умолчанию Провайдер MySQL
System.Web.SessionState.InProcSessionStateStore MySql.Web.SessionState.MySqlSessionStateStore

Ппровайдер состояния сеанса MySQL использует немного отличающуюся капитализацию имени класса по сравнению с другими провайдерами MySQL.

Установка провайдеров

Установка Connector/NET установит провайдеров и зарегистрирует их в конфигурационном файле .NET machine.config вашей машины. Дополнительные созданные записи приведут к секции system.web, подобной следующему коду:

<system.web>
  <processModel autoConfig="true" />
  <httpHandlers />
  <membership>
    <providers>
      <add name="AspNetSqlMembershipProvider"
        type="System.Web.Security.SqlMembershipProvider, System.Web,
        Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
        connectionStringName="LocalSqlServer" enablePasswordRetrieval="false"
        enablePasswordReset="true" requiresQuestionAndAnswer="true"
        applicationName="/" requiresUniqueEmail="false"
        passwordFormat="Hashed" maxInvalidPasswordAttempts="5"
        minRequiredPasswordLength="7" minRequiredNonalphanumericCharacters="1"
        passwordAttemptWindow="10" passwordStrengthRegularExpression="" />
      <add name="MySQLMembershipProvider"
        type="MySql.Web.Security.MySQLMembershipProvider, MySql.Web,
        Version=6.1.1.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d"
        connectionStringName="LocalMySqlServer"
        enablePasswordRetrieval="false" enablePasswordReset="true"
        requiresQuestionAndAnswer="true" applicationName="/"
        requiresUniqueEmail="false" passwordFormat="Clear"
        maxInvalidPasswordAttempts="5" minRequiredPasswordLength="7"
        minRequiredNonalphanumericCharacters="1" passwordAttemptWindow="10"
        passwordStrengthRegularExpression="" />
    </providers>
  </membership>

  <profile>
    <providers>
      <add name="AspNetSqlProfileProvider"
        connectionStringName="LocalSqlServer" applicationName="/"
        type="System.Web.Profile.SqlProfileProvider, System.Web,
        Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
      <add name="MySQLProfileProvider"
        type="MySql.Web.Profile.MySQLProfileProvider, MySql.Web,
        Version=6.1.1.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d"
        connectionStringName="LocalMySqlServer" applicationName="/" />
    </providers>
  </profile>

  <roleManager>
    <providers>
      <add name="AspNetSqlRoleProvider"
        connectionStringName="LocalSqlServer" applicationName="/"
        type="System.Web.Security.SqlRoleProvider, System.Web,
        Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
      <add name="AspNetWindowsTokenRoleProvider" applicationName="/"
        type="System.Web.Security.WindowsTokenRoleProvider, System.Web,
        Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
      <add name="MySQLRoleProvider"
        type="MySql.Web.Security.MySQLRoleProvider, MySql.Web,
        Version=6.1.1.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d"
        connectionStringName="LocalMySqlServer" applicationName="/" />
    </providers>
  </roleManager>
</system.web>

У каждого типа провайдера могут быть многократные реализации провайдера. Провайдер по умолчанию может также быть установлен, используя атрибут defaultProvider, но обычно это установлено в файле web.config вручную или при помощи инструмента конфигурирования ASP.NET.

Во время написания MySqlSessionStateStore не добавляется к machine.config во время установки, и тем самым добавляют следующее:

<sessionState>
  <providers>
    <add name="MySqlSessionStateStore"
      type="MySql.Web.SessionState.MySqlSessionStateStore, MySql.Web,
      Version=6.1.1.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d"
      connectionStringName="LocalMySqlServer" applicationName="/" />
  </providers>
</sessionState>

Провайдер состояния сеанса использует атрибут customProvider вместо defaultProvider, чтобы установить провайдера по умолчанию. Типичный файл web.config включает:

<system.web>
  <membership defaultProvider="MySQLMembershipProvider" />
  <roleManager defaultProvider="MySQLRoleProvider" />
  <profile defaultProvider="MySQLProfileProvider" />
  <sessionState customProvider="MySqlSessionStateStore" />
  <compilation debug="false">
...

Это устанавливает провайдеров MySQL по умолчанию в этом веб-приложении.

Провайдери осуществляются в файле mysql.web.dll и этот файл может быть найден в вашем инсталляционном каталоге Connector/NET. Нет никакой потребности управлять любым типом скрипта SQL, чтобы настроить схему базы данных, поскольку провайдери создают и ведут надлежащую схему автоматически.

Использование провайдеров

Самый легкий способ начать использовать провайдеров состоит в том, чтобы использовать инструмент конфигурирования ASP.NET, который доступен на панели инструментов Solution Explorer, когда у вас есть загруженный проект веб-сайта.

В веб-страницах, которые открываются, можно выбрать членство MySQL и ролевых провайдеров, выбрав провайдера для каждой области.

Когда провайдер устанавливается, это создает фиктивную строку подключения, названную LocalMySqlServer. Хотя это должно быть сделано так, чтобы провайдер работал в инструменте конфигурирования ASP.NET, вы перекрываете эту строку подключения в вашем файле web.config. Вы делаете это удалением фиктивной строки подключения и затем добавлением надлежащей, как показано в следующем примере:

<connectionStrings>
  <remove name="LocalMySqlServer"/>
  <add name="LocalMySqlServer" connectionString="server=xxx;uid=xxx;pwd=xxx;database=xxx"/>
</connectionStrings>

Необходимо определить базу данных в этой связи.

Вместо того, чтобы вручную редактировать конфигурационные файлы, рассмотрите использование инструмента MySQL Application Configuration в MySQL for Visual Studio, чтобы формировать вашу желаемую установку провайдера. Инструмент изменяет ваш файл Web.config к желаемой конфигурации. Обучающая программа для выполнения этого доступна в MySQL Application Configuration Tool.

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

Развертывание

Чтобы использовать провайдеров на рабочем сервере, распределите сборки MySql.Data и MySql.Web, зарегистрируйте их в Global Assembly Cache или храните их в каталоге bin/ вашего приложения.

5.17. Работа с Partial Trust/Medium Trust

Приложения .NET работают под данным трастовым уровнем. Нормальные приложения работают под полным доверием, в то время как веб-приложениями, которые ведутся в общих средах, обычно управляют под частичным трастовым уровнем (также известный как medium trust). Некоторые провайдери услуг хостинга ведут общие приложения в своих собственных пулах приложений и позволяют запросу работать под полным доверием, но эта конфигурация относительно редка. Поддержка MySQL Connector/NET для частичного доверия улучшилась со временем, чтобы упростить конфигурацию и процесс развертывания для провайдеров услуг хостинга.

5.17.1. Эволюция поддержки Partial Trust через версии Connector/NET

Частичная трастовая поддержка MySQL Connector/NET улучшилась повсюду в версиях 6.5.x и 6.6.x. Последние улучшения действительно требуют некоторых изменений конфигурации в существующем развертывании. Вот резюме изменений для каждой версии.

6.6.4 и выше: библиотека может быть внутри или снаружи GAC

Теперь можно установить библиотеку MySql.Data.dll в Global Assembly Cache (GAC), как объяснено в разделе 5.17.2, или в каталоге bin (или lib, как объяснено в разделе 5.17.3. Если библиотека не находится в GAC, единственный поддержанный протокол это TCP/IP.

6.5.1 и выше: Partial Trust требует библиотеки в GAC

Connector/NET 6.5 полностью позволяет нашему провайдеру работать в частичной трастовой окружающей среде, когда библиотека устанавливается в Global Assembly Cache (GAC). Новый класс MySqlClientPermission, полученный из класса .NET DBDataPermission, помогает упростить установку разрешения.

5.0.8/5.1.3 и выше: Partial Trust требует разрешений сокета

Начиная с этих версий, Connector/NET может использоваться под частичным доверием, которое было изменено, чтобы позволить использование сокетов для коммуникации. По умолчанию частичное доверие не включает SocketPermission. Connector/NET использует сокеты, чтобы работать с сервером MySQL, таким образом, провайдер услуг хостинга должен создать новый трастовый уровень, который является точным клоном частичного доверия, но этому добавили следующие разрешения:

  • System.Net.SocketPermission

  • System.Security.Permissions.ReflectionPermission

  • System.Net.DnsPermission

  • System.Security.Permissions.SecurityPermission

До 5.0.8/5.1.3: Partial не поддерживается

Connector/NET до 5.0.8 и 5.1.3 не был совместим с частичным трастовым хостингом.

5.17.2. Настройка Partial Trust с библиотекой Connector/NET в GAC

Если библиотека устанавливается в GAC, необходимо включать выбор связи includesecurityasserts=true в вашей строке подключения. Это новое требование MySQL Connector/NET 6.6.4.

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

  1. Установка Connector/NET: версия 6.6.1 или выше, 6.5.4 или выше.

  2. После установки библиотеки сделайте следующие изменения конфигурации:

    В секции SecurityClasses добавьте определение для класса MySqlClientPermission , включая версию.

    <configuration>
      <mscorlib>
      <security>
      <policy>
      <PolicyLevel version="1">
      <SecurityClasses>
      ....
      <SecurityClass Name="MySqlClientPermission"
        Description="MySql.Data.MySqlClient.MySqlClientPermission,
        MySql.Data, Version=6.6.4.0, Culture=neutral,
        PublicKeyToken=c5687fc88969c44d" />
    

    Прокрутите вниз к секции ASP.Net:

    <PermissionSetclass="NamedPermissionSet"version="1"Name="ASP.Net">
    

    Добавьте новую запись для подробной конфигурации класса MySqlClientPermission:

    <IPermission class="MySqlClientPermission" version="1"
      Unrestricted="true"/>
    

    Эта конфигурация наиболее обобщенный путь, который включает все ключевые слова.

  3. Настройте сервер MySQL, чтобы принять связи канала, добавляя опцию --enable-named-pipe в командной строке. Если вам нужно больше информации об этом, посмотрите Installing MySQL on Microsoft Windows.

  4. Подтвердите, что провайдер услуг хостинга установил библиотеку Connector/NET (MySql.Data.dll) в GAC.

  5. Произвольно, провайдер услуг хостинга может давать разрешения глобально при помощи нового класса MySqlClientPermission в трастовой политике. Альтернатива должна глобально позволить разрешения System.Net.SocketPermission, System.Security.Permissions.ReflectionPermission, System.Net.DnsPermission и System.Security.Permissions.SecurityPermission .

  6. Создайте простое веб-приложение, используя Visual Studio 2010.

  7. Добавьте ссылку в своем приложении на библиотеку MySql.Data.MySqlClient.

  8. Отредактируйте ваш файл web.config так, чтобы ваше приложение работало, используя трастовый уровень Medium:

    <system.web>
      <trust level="Medium"/>
    </system.web>
    
  9. Добавьте пространство имен MySql.Data.MySqlClient к вашей странице серверного кода.

  10. Определите строку подключения немного отличающимися способами в зависимости от версии Connector/NET.

    Только 6.6.4 или выше: Чтобы использовать связи в любом веб-приложении, которое будет работать в доверии Medium, добавьте к строке подключения опцию includesecurityasserts. includesecurityasserts=true это запросит для библиотеки следующие разрешения при необходимости: SocketPermissions, ReflectionPermissions, DnsPermissions, SecurityPermissions среди других, которых не предоставляют на средних трастовых уровнях.

    Connector/NET 6.6.3 или ранее: Никакое специальное урегулирование для безопасности не нужно в строке подключения.

    MySqlConnectionStringBuilder myconnString = new MySqlConnectionStringBuilder("server=localhost;User Id=root;database=test");
    myconnString.PipeName = "MySQL55";
    myconnString.ConnectionProtocol = MySqlConnectionProtocol.Pipe;
    // Following attribute is a new requirement when the library is in the GAC.
    // Could also be done by adding includesecurityasserts=true; to the string literal
    // in the constructor above.
    // Not needed with Connector/NET 6.6.3 and earlier.
    myconnString.IncludeSecurityAsserts = true;
    
  11. Определите MySqlConnection:

    MySqlConnection myconn = new MySqlConnection(myconnString.ConnectionString);
    myconn.Open();
    
  12. Получите некоторые данные из своих таблиц:

    MySqlCommand cmd = new MySqlCommand("Select * from products", myconn);
    MySqlDataAdapter da = new MySqlDataAdapter(cmd);
    DataSet1 tds = new DataSet1();
    da.Fill(tds, tds.Tables[0].TableName);
    GridView1.DataSource = tds;
    GridView1.DataBind();
    myconn.Close()
    
  13. Выполните программу. Это должно выполниться успешно, не требуя никакого специального кода или столкнувшись с любыми проблемами безопасности.

5.17.3. Настройка Partial Trust с библиотекой Connector/NET не в GAC

Развертывая веб-приложение в окружении Shared Hosted, где эта окружающая среда формируется, чтобы запустить все .NET-приложения под частичным или средним трастовым уровнем, вы не можете установить библиотеку MySQL Connector/NET в GAC. Вместо этого вы помещаете ссылку на библиотеку в каталог bin или lib в проекте или решении. В этом случае вы формируете безопасность по-другому чем тогда, когда библиотека находится в GAC.

Connector/NET обычно используется приложениями в среде Windows, где коммуникация по умолчанию используется через сокеты или TCP/IP. Для этого протокола необходимо иметь необходимые разрешения сокета в веб-конфигурационном файле следующим образом:

  1. Откройте средний трастовый стратегический веб-конфигурационный файл, который должен находиться под этим каталогом:

    %windir%\Microsoft.NET\Framework\{version}\CONFIG\web_mediumtrust.config
    

    Используйте Framework64 в пути вместо Framework, если вы используете 64-битную установку структуры.

  2. Определите местонахождение тэга SecurityClasses:

    <SecurityClass Name="SocketPermission"
      Description="System.Net.SocketPermission, System, Version=4.0.0.0,
      Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
    
  3. Прокрутите вниз и ищите следующий PermissionSet:

    <PermissionSet version="1" Name="ASP.Net">
    
  4. Добавьте следующую внутреннюю часть PermissionSet:

    <IPermission class="SocketPermission" version="1" Unrestricted="true" />
    

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

    Кроме того, начиная с MySQLClientPermissions, класс не добавляется к средней трастовой политике, вы не можете использовать его. Эта конфигурация это минимум, требуемый, чтобы работать с Connector/NET без GAC.

Поиск

 

Найди своих коллег!

Вы можете направить письмо администратору этой странички, Алексею Паутову. mailto:alexey.v.pautov@mail.ru