MySQL CRUD Operations in .NET MAUI
.NET MAUI (Multi-platform App UI) is a cross-platform framework for building desktop and mobile applications with C# and XAML. With its help, developers can create applications running on Windows, Mac, iOS, and Andriod Operating systems, all from one Codebase.
MySQL is one of the most popular databases for building web applications. It is also open-source, allowing everyone to establish the database instance and connect to it. Database connectivity is essential because the application requires a reliable data source. Therefore, developers must ensure a quick and smooth connection to the database, as well as efficient data retrieval and management within the application.
In this tutorial, we will explore integration MySQL with a MAUI application, allowing us to design and manage the database directly from the C# code.
Download and activate dotConnect for MySQL
30-day free trial version
Download and install dotConnect for MySQL directly on your machine, or install the Devart.Data.MySQL NuGet package.
To activate a 30-day trial, use the license key assigned to you after completing the registration on the Devart website.
Full version
After purchasing the full version, go to your profile's Licenses page. Choose your product and click Details. Here, you'll find the license details and the Activation Key.
To activate a connection in your application, add the License Key to your connection string.
The next step is creating a .NET MAUI project.
Perform CRUD operations
In addition to establishing connections, dotConnect for MySQL also enables us to deal with essential database operations such as CREATE, READ, UPDATE, and DELETE directly. Let's take a closer look at how these operations can be performed.
INSERT MySQL data
To insert data into an empty table in the MySQL database, we first need to create a class based on the table we have just created. Right-click your solution and add a class named Actor.cs. Inside that class, copy the below piece:
public class Actor
{
public int ActorId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime LastUpdate { get; set; }
}
Next, in DatabaseConnectionClass, add a new method:
public static void AddActor(Actor actor)
{
MySqlConnection conn = new MySqlConnection($"{databasePath};LicenseKey={licenseKey.yourLicensekey};");
MySqlCommand cmd = new MySqlCommand();
cmd.CommandText = "INSERT INTO actor (first_name, last_name, last_update) VALUES (@first_name, @last_name, @last_update);";
cmd.Parameters.Add(new MySqlParameter("@first_name", actor.FirstName));
cmd.Parameters.Add(new MySqlParameter("@last_name", actor.LastName));
cmd.Parameters.Add(new MySqlParameter("@last_update", actor.LastUpdate));
cmd.Connection = conn;
conn.Open();
try
{
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine($"An error occured; {ex.Message}");
}
}
Now, let's configure our application view. In MySQLDemo.xaml, edit it so it looks like this:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MySQLMAUI.MySQLDemo"
Title="MySQLDemo">
<StackLayout>
<StackLayout x:Name="InsertSection" IsVisible="False" Padding="10">
<Label Text="First Name:" />
<Entry x:Name="InsertFirstNameEntry" Placeholder="Enter first name" />
<Label Text="Second Name:" />
<Entry x:Name="InsertSecondNameEntry" Placeholder="Enter second name" />
<Label x:Name="InsertErrorLabel" TextColor="Red" IsVisible="False" />
<Button Text="Insert" Clicked="OnInsertButtonClicked" WidthRequest="80" />
</StackLayout>
<Button x:Name="InsertActor" Text="Insert New Actor" Clicked="OnShowInsertSectionClicked" WidthRequest="150" />
</StackLayout>
</ContentPage>
In MySQLDemo.xaml.cs Code-behind, add two methods inside the MySQLDemo class:
private void OnShowInsertSectionClicked(object sender, EventArgs e)
{
InsertFirstNameEntry.Text = string.Empty;
InsertSecondNameEntry.Text = string.Empty;
// Show the insert section and hide the Insert actor button
InsertSection.IsVisible = true;
InsertActor.IsVisible = false;
}
private void OnInsertButtonClicked(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(InsertFirstNameEntry.Text) ||
string.IsNullOrWhiteSpace(InsertSecondNameEntry.Text))
{
// Show error message
InsertErrorLabel.Text = "Both fields are required.";
InsertErrorLabel.IsVisible = true;
return;
}
// Create a new actor object with the inserted values
var newActor = new Actor
{
FirstName = InsertFirstNameEntry.Text,
LastName = InsertSecondNameEntry.Text,
LastUpdate = DateTime.Now
};
// Add the new actor to the database
DatabaseConnectionClass.AddActor(newActor);
// Refresh the CollectionView
BindingContext = null;
BindingContext = this;
// Hide the insert section
InsertSection.IsVisible = false;
}
Run the code and click Go to Demo page:
Click Insert new actor, enter the actor's first name and last name, and click Insert.
READ MySQL data
Now that we have inserted a record into the table, we need a way to see what was added.
In DataBaseConnectionClass, add the below new method to get a list of all actors:
public static ListGetActors() { List actors = new List (); MySqlConnection conn = new MySqlConnection($"{databasePath};LicenseKey={licenseKey.yourLicensekey};"); MySqlCommand cmd = new (); cmd.CommandText = "SELECT * FROM actor;"; cmd.Connection = conn; conn.Open(); MySqlDataReader reader = cmd.ExecuteReader(); while (reader.Read()) { Actor actor = new Actor { ActorId = Convert.ToInt32(reader["actor_id"]), FirstName = reader["first_name"].ToString(), LastName = reader["last_name"].ToString(), LastUpdate = Convert.ToDateTime(reader["last_update"]) }; actors.Add(actor); } return actors; }
Now, in MySQLDemo.xaml, edit the XAML file so it looks as follows:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MySQLMAUI.MySQLDemo"
Title="MySQLDemo">
<StackLayout>
<CollectionView ItemsSource="{Binding Actors}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="2" RowDefinitions="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Label Text="{Binding ActorId}"
Grid.Column="0"
VerticalOptions="Center"
HorizontalOptions="Center"
Padding="3"
Margin="0.5" />
<Label Text="{Binding FirstName}"
Grid.Column="1"
VerticalOptions="Center"
HorizontalOptions="Center"
Padding="3"
Margin="0.5" />
<Label Text="{Binding LastName}"
Grid.Column="2"
VerticalOptions="Center"
HorizontalOptions="Center"
Padding="3"
Margin="0.5" />
<Label Text="{Binding LastUpdate}"
Grid.Column="3"
VerticalOptions="Center"
HorizontalOptions="Center"
Padding="3"
Margin="0.5" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<StackLayout x:Name="InsertSection" IsVisible="False" Padding="10">
<Label Text="First Name:" />
<Entry x:Name="InsertFirstNameEntry" Placeholder="Enter first name" />
<Label Text="Second Name:" />
<Entry x:Name="InsertSecondNameEntry" Placeholder="Enter second name" />
<Label x:Name="InsertErrorLabel" TextColor="Red" IsVisible="False" />
<Button Text="Insert" Clicked="OnInsertButtonClicked" WidthRequest="80" />
</StackLayout>
<Button x:Name="InsertActor" Text="Insert New Actor" Clicked="OnShowInsertSectionClicked" WidthRequest="150" />
</StackLayout>
</ContentPage>
In MySQLDemo.xaml.cs file, add a new property for a list of actors, initialize it in the class constructor, and set Binding in the following way:
public partial class MySQLDemo : ContentPage
{
public List Actors { get; set; }
public MySQLDemo()
{
InitializeComponent();
//DatabaseConnectionClass.CreateActorTable();
Actors = DatabaseConnectionClass.GetActors();
// Set the BindingContext
BindingContext = this;
}
....
}
Now, when you run the application and navigate to MySQLDemo, you can see the data.
UPDATE MySQL Data
Assume we want to change the actor's last name. In DataBaseConnectionClass, add a new method called UpdateActor:
public static void UpdateActor(Actor actor)
{
MySqlConnection conn = new MySqlConnection($"{databasePath};LicenseKey={licenseKey.yourLicensekey};");
MySqlCommand cmd = new MySqlCommand();
cmd.CommandText = "UPDATE actor SET first_name = @first_name, last_name = @last_name, last_update = @last_update WHERE actor_id = @actor_id;";
cmd.Parameters.Add(new MySqlParameter("@first_name", actor.FirstName));
cmd.Parameters.Add(new MySqlParameter("@last_name", actor.LastName));
cmd.Parameters.Add(new MySqlParameter("@last_update", actor.LastUpdate));
cmd.Parameters.Add(new MySqlParameter("@actor_id", actor.ActorId));
cmd.Connection = conn;
conn.Open();
try
{
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine($"An error occured; {ex.Message}");
}
}
Next, in the MySQLDemo.xaml file, replace the code with the one below:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MySQLMAUI.MySQLDemo"
Title="MySQLDemo">
<StackLayout>
<CollectionView ItemsSource="{Binding Actors}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="2" RowDefinitions="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Text="{Binding ActorId}"
Grid.Column="0"
VerticalOptions="Center"
HorizontalOptions="Center"
Padding="3"
Margin="0.5" />
<Label Text="{Binding FirstName}"
Grid.Column="1"
VerticalOptions="Center"
HorizontalOptions="Center"
Padding="3"
Margin="0.5" />
<Label Text="{Binding LastName}"
Grid.Column="2"
VerticalOptions="Center"
HorizontalOptions="Center"
Padding="3"
Margin="0.5" />
<Label Text="{Binding LastUpdate}"
Grid.Column="3"
VerticalOptions="Center"
HorizontalOptions="Center"
Padding="3"
Margin="0.5" />
<Button Text="Update"
Grid.Column="4"
VerticalOptions="Center"
HorizontalOptions="Center"
Clicked="OnUpdateButtonClicked"
CommandParameter="{Binding ActorId}" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<StackLayout x:Name="UpdateSection" IsVisible="False" Padding="10">
<Label Text="Update First Name:" />
<Entry x:Name="UpdateFirstNameEntry" Placeholder="Enter new first name" />
<Label Text="Update Second Name:" />
<Entry x:Name="UpdateSecondNameEntry" Placeholder="Enter new Last name" />
<Label x:Name="UpdateErrorLabel" TextColor="Red" IsVisible="False" />
<Button Text="Go" Clicked="OnGoButtonClicked" />
</StackLayout>
<StackLayout x:Name="InsertSection" IsVisible="False" Padding="10">
<Label Text="First Name:" />
<Entry x:Name="InsertFirstNameEntry" Placeholder="Enter first name" />
<Label Text="Second Name:" />
<Entry x:Name="InsertSecondNameEntry" Placeholder="Enter second name" />
<Label x:Name="InsertErrorLabel" TextColor="Red" IsVisible="False" />
<Button Text="Insert" Clicked="OnInsertButtonClicked" WidthRequest="80" />
</StackLayout>
<Button x:Name="InsertActor" Text="Insert New Actor" Clicked="OnShowInsertSectionClicked" WidthRequest="150" />
</StackLayout>
</ContentPage>
We have added a new button called Update and a section for inputting the updated values.
In the MySQLDemo.xaml.cs Code-behind, we need to add a new property:
private Actor? _selectedActor;
Also, we need to add two new methods: OnUpdateButtonClicked and OnGoButtonClicked.
private void OnUpdateButtonClicked(object sender, EventArgs e)
{
var button = sender as Button;
var actorId = (int)button.CommandParameter;
// Find the actor in the list by ID
_selectedActor = Actors.FirstOrDefault(p => p.ActorId == actorId);
if (_selectedActor != null)
{
// Populate Entry fields with existing values
UpdateFirstNameEntry.Text = _selectedActor.FirstName;
UpdateSecondNameEntry.Text = _selectedActor.LastName;
// Show the update section
UpdateSection.IsVisible = true;
}
}
private void OnGoButtonClicked(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(UpdateFirstNameEntry.Text) ||
string.IsNullOrWhiteSpace(UpdateSecondNameEntry.Text))
{
// Show error message
UpdateErrorLabel.Text = "Both fields are required.";
UpdateErrorLabel.IsVisible = true;
return;
}
if (_selectedActor != null)
{
// Create a new actor object with the updated values
var updatedActor = new Actor
{
ActorId = _selectedActor.ActorId,
FirstName = UpdateFirstNameEntry.Text,
LastName = UpdateSecondNameEntry.Text,
LastUpdate = DateTime.Now
};
// Update the actor in the database
DatabaseConnectionClass.UpdateActor(updatedActor);
// Hide the update section
UpdateSection.IsVisible = false;
}
}
When the code is run, a new Update button is displayed:
Clicking this button adds the insert modal to insert new values.
Click Go, and the record gets updated:
DELETE MySQL Data
Let's try to remove an actor from our database. Our test table includes the Johnny Blaze record that we need to remove:
In DataBaseConnectionClass, add a method called DeleteActor:
public static void DeleteActor(int actorId)
{
MySqlConnection conn = new MySqlConnection($"{databasePath};LicenseKey={licenseKey.yourLicensekey};");
MySqlCommand cmd = new MySqlCommand();
cmd.CommandText = "DELETE FROM actor WHERE actor_id = @actor_id;";
cmd.Parameters.Add(new MySqlParameter("@actor_id", actorId));
cmd.Connection = conn;
conn.Open();
try
{
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine($"An error occured; {ex.Message}");
}
}
Then, in MySQLDemo.xaml, add a new button under the Update button.
<Button Text="Delete"
Grid.Column="5"
VerticalOptions="Center"
HorizontalOptions="Center"
Clicked="OnDeleteButtonClicked"
CommandParameter="{Binding ActorId}" />
Add a new column definition in Grid.ColumnDefinitions.
<ColumnDefinition Width="Auto" />
Finally, add the method for the OnDeleteButtonClicked in MySQLDemo.xaml.cs Code-behind:
private void OnDeleteButtonClicked(object sender, EventArgs e)
{
var button = sender as Button;
var actorId = (int)button.CommandParameter;
// Find the actor in the database by ID
DatabaseConnectionClass.DeleteActor(actorId);
this.Actors = DatabaseConnectionClass.GetActors();
BindingContext = null;
BindingContext = this;
}
When you run the application, you can see a new Delete button:
Clicking this butting removes the record: