Data Access with MySQL using ADO.NET

This document provides a comprehensive guide on how to access and manipulate data in a MySQL database using ADO.NET in .NET applications.

MySQL is a popular open-source relational database management system. ADO.NET provides a set of classes that expose data access services to the .NET Framework. By combining ADO.NET with a MySQL connector, you can seamlessly integrate your .NET applications with MySQL databases.

Prerequisites

Installing MySQL Connector/NET

The easiest way to add MySQL Connector/NET to your project is by using the NuGet Package Manager. Open your project in Visual Studio or use the .NET CLI:

dotnet add package MySql.Data

This command will download and install the necessary libraries for connecting to MySQL.

Establishing a Connection

To interact with a MySQL database, you first need to establish a connection. The `MySqlConnection` class from the `MySql.Data.MySqlClient` namespace is used for this purpose. A connection string specifies the details required to connect to the database, such as the server address, username, password, and database name.

using MySql.Data.MySqlClient;
using System;

public class DatabaseConnector
{
    private string connectionString;

    public DatabaseConnector(string server, string database, string user, string password)
    {
        connectionString = $"SERVER={server};DATABASE={database};UID={user};PASSWORD={password};";
    }

    public void TestConnection()
    {
        using (MySqlConnection connection = new MySqlConnection(connectionString))
        {
            try
            {
                connection.Open();
                Console.WriteLine("Connection to MySQL successful!");
                // Connection is open, you can perform database operations here
            }
            catch (MySqlException ex)
            {
                Console.WriteLine($"Error connecting to MySQL: {ex.Message}");
            }
            finally
            {
                if (connection.State == System.Data.ConnectionState.Open)
                {
                    connection.Close();
                    Console.WriteLine("Connection closed.");
                }
            }
        }
    }
}

Executing Commands

Once a connection is established, you can execute SQL commands using `MySqlCommand`. You can perform operations like inserting, updating, deleting, and querying data.

Reading Data with `MySqlDataReader`

The `MySqlDataReader` is an efficient way to read a forward-only stream of rows from a MySQL database. It's ideal for retrieving large result sets without loading them entirely into memory.

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

public class DataReaderExample
{
    private string connectionString;

    public DataReaderExample(string server, string database, string user, string password)
    {
        connectionString = $"SERVER={server};DATABASE={database};UID={user};PASSWORD={password};";
    }

    public void ReadProducts()
    {
        string query = "SELECT ProductID, ProductName, Price FROM Products;";

        using (MySqlConnection connection = new MySqlConnection(connectionString))
        {
            using (MySqlCommand command = new MySqlCommand(query, connection))
            {
                try
                {
                    connection.Open();
                    MySqlDataReader reader = command.ExecuteReader();

                    if (reader.HasRows)
                    {
                        while (reader.Read())
                        {
                            Console.WriteLine($"ID: {reader["ProductID"]}, Name: {reader["ProductName"]}, Price: {reader["Price"]}");
                        }
                    }
                    else
                    {
                        Console.WriteLine("No products found.");
                    }
                    reader.Close();
                }
                catch (MySqlException ex)
                {
                    Console.WriteLine($"Error reading data: {ex.Message}");
                }
            }
        }
    }
}

Executing Non-Query Commands

For SQL statements that do not return a result set (like `INSERT`, `UPDATE`, `DELETE`, `CREATE TABLE`), you can use `ExecuteNonQuery()`. This method returns the number of rows affected by the command.

using MySql.Data.MySqlClient;
using System;

public class NonQueryExample
{
    private string connectionString;

    public NonQueryExample(string server, string database, string user, string password)
    {
        connectionString = $"SERVER={server};DATABASE={database};UID={user};PASSWORD={password};";
    }

    public int AddNewProduct(string productName, decimal price)
    {
        string query = "INSERT INTO Products (ProductName, Price) VALUES (@Name, @Price);";
        int rowsAffected = 0;

        using (MySqlConnection connection = new MySqlConnection(connectionString))
        {
            using (MySqlCommand command = new MySqlCommand(query, connection))
            {
                command.Parameters.AddWithValue("@Name", productName);
                command.Parameters.AddWithValue("@Price", price);

                try
                {
                    connection.Open();
                    rowsAffected = command.ExecuteNonQuery();
                    Console.WriteLine($"{rowsAffected} row(s) inserted successfully.");
                }
                catch (MySqlException ex)
                {
                    Console.WriteLine($"Error inserting data: {ex.Message}");
                }
            }
        }
        return rowsAffected;
    }
}

Using `MySqlDataAdapter` and `DataSet`/`DataTable`

For scenarios where you need to work with data in memory, such as manipulating datasets or working offline, ADO.NET provides `MySqlDataAdapter`. This class acts as a bridge between a `DataSet` (or `DataTable`) and a MySQL data source. It can fill a `DataSet` with data and resolve changes made to the `DataSet` back to the database.

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

public class DataAdapterExample
{
    private string connectionString;

    public DataAdapterExample(string server, string database, string user, string password)
    {
        connectionString = $"SERVER={server};DATABASE={database};UID={user};PASSWORD={password};";
    }

    public DataTable GetProductsDataTable()
    {
        DataTable dataTable = new DataTable();
        string query = "SELECT ProductID, ProductName, Price FROM Products;";

        using (MySqlConnection connection = new MySqlConnection(connectionString))
        {
            using (MySqlDataAdapter adapter = new MySqlDataAdapter(query, connection))
            {
                try
                {
                    adapter.Fill(dataTable);
                    Console.WriteLine($"Loaded {dataTable.Rows.Count} products into DataTable.");
                }
                catch (MySqlException ex)
                {
                    Console.WriteLine($"Error filling DataTable: {ex.Message}");
                }
            }
        }
        return dataTable;
    }

    public void UpdateProductPrice(int productId, decimal newPrice)
    {
        DataTable dataTable = GetProductsDataTable(); // Get data into memory first

        DataRow[] rows = dataTable.Select($"ProductID = {productId}");
        if (rows.Length > 0)
        {
            rows[0]["Price"] = newPrice;
            rows[0].AcceptChanges(); // Mark the change as accepted

            string updateQuery = "UPDATE Products SET Price = @Price WHERE ProductID = @ID;";
            using (MySqlConnection connection = new MySqlConnection(connectionString))
            {
                using (MySqlCommand command = new MySqlCommand(updateQuery, connection))
                {
                    command.Parameters.AddWithValue("@Price", newPrice);
                    command.Parameters.AddWithValue("@ID", productId);

                    // For simplicity, we are executing a single update.
                    // In a real application, you might use MySqlDataAdapter's Update method
                    // to handle updates for multiple rows within the DataTable.
                    try
                    {
                        connection.Open();
                        command.ExecuteNonQuery();
                        Console.WriteLine($"Product {productId} price updated to {newPrice}.");
                    }
                    catch (MySqlException ex)
                    {
                        Console.WriteLine($"Error updating price: {ex.Message}");
                    }
                }
            }
        }
        else
        {
            Console.WriteLine($"Product with ID {productId} not found.");
        }
    }
}

Note on Connection Pooling: MySQL Connector/NET automatically implements connection pooling. This means that instead of creating a new connection every time, it reuses existing connections, significantly improving performance for applications that frequently open and close connections.

Best Practices

Tip: For complex data manipulation or Object-Relational Mapping (ORM) needs, consider using Entity Framework Core, which provides a higher-level abstraction over ADO.NET and simplifies database interactions significantly.

By following these guidelines and examples, you can effectively integrate MySQL databases into your .NET applications using ADO.NET.