Skip to ContentSkip to Content
ProvidersMySQL / MariaDB

Forge.Repository.MySql

The MySQL provider uses Pomelo.EntityFrameworkCore.MySql which supports both MySQL (5.7+, 8.0+) and MariaDB (10.3+). It exposes the standard Forge configuration API for pooling, retries, and timeouts.

NuGet: Forge.Repository.MySql


Installation

dotnet add package Forge.Repository dotnet add package Forge.Repository.MySql

Registration

using Forge.DbTuner; using Forge.MySql; builder.Services.AddForgeRepositoryMySql<AppDbContext>( connectionString: builder.Configuration.GetConnectionString("Default")!, poolingOptions: new ForgeDbContextPoolingOptions { EnablePooling = true, MinPoolSize = 2, MaxPoolSize = 30, }, configure: tuner => { tuner.SetRetry(3); // retry transient failures up to 3 times tuner.SetTimeout(30); // command timeout of 30 seconds tuner.ApplySpatial(); // enable spatial data support tuner.EnableLazyLoading(); // enable lazy loading of navigation properties });

Connection String Reference

// appsettings.json // MySQL local "Default": "Server=localhost;Port=3306;Database=myapp;User=root;Password=root;" // MySQL production "Default": "Server=prod-mysql.internal;Port=3306;Database=myapp;User=appuser;Password=secret;SslMode=Required;" // MariaDB "Default": "Server=localhost;Port=3306;Database=myapp;User=root;Password=root;AllowUserVariables=true;" // PlanetScale (MySQL-compatible) "Default": "Server=aws.connect.psdb.cloud;Database=myapp;User=myuser;Password=pscale_pw_...;SslMode=VerifyFull;"

Forge injects Pooling, MinPoolSize, and MaxPoolSize into the MySQL connection string builder. Do not set pool properties in the raw connection string.


DbContext

using Forge.Repository; using Microsoft.EntityFrameworkCore; public class AppDbContext(DbContextOptions<AppDbContext> options) : Forge.Repository.DbContext(options) { public DbSet<Product> Products { get; set; } public DbSet<Order> Orders { get; set; } public DbSet<Customer> Customers { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); //Apply all configurations from assembly modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly); } }

ModelBuilder Configuration

using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; public class OrderConfiguration : IEntityTypeConfiguration<Order> { public void Configure(EntityTypeBuilder<Order> builder) { builder.ToTable("Orders"); // Global query filter to exclude soft-deleted records builder.HasQueryFilter(x => !x.IsDeleted); // Base builder.HasKey(x => x.Id); builder.Property(x => x.Id).HasMaxLength(36); // Auditable builder.Property(x => x.CreatedBy).HasMaxLength(36).IsRequired(); builder.Property(x => x.CreatedOn).IsRequired(); builder.Property(x => x.ModifiedBy).HasMaxLength(36).IsRequired(false); builder.Property(x => x.ModifiedOn); builder.Property(x => x.IsDeleted).IsRequired(); // Order builder.Property(x => x.OrderDate).IsRequired(); builder.Property(x => x.TotalAmount).IsRequired().HasPrecision(18, 4); // Relationships builder.HasMany(x => x.OrderProducts) .WithOne(x => x.Order) .HasForeignKey(x => x.OrderId) .OnDelete(DeleteBehavior.NoAction); } }

Migrations

# Add a migration dotnet ef migrations add InitialCreate --project src/MyApp # Apply migrations dotnet ef database update --project src/MyApp

Applying migrations programmatically at startup

// Program.cs — apply pending migrations on startup using (var scope = app.Services.CreateScope()) { var initializer = scope.ServiceProvider.GetRequiredService<IDbInitializer>(); await initializer.InitializeSqlDb(scope, default); }

DbInitializer

DbInitializer is a Forge-provided utility designed to safely execute EF Core migrations during application startup. It features an optional ignoreMigration parameter that accepts a target environment name. When this parameter matches the current ASPNETCORE_ENVIRONMENT variable, automatic migrations are bypassed.

This mechanism is especially valuable in development workflows: it prevents a developer’s local workstation from accidentally triggering unintended schema changes when connecting to a shared, UAT, or Production database.

public interface IDbInitializer { Task InitializeSqlDb( IServiceScope scope, CancellationToken cancellationToken, string ignoreMigration = "Development"); }
// Skip any pending migration if the environment is "Development" await initializer.InitializeSqlDb(scope, ct, ignoreMigration: "Development");

SeedData

Asynchronously seeds initial data for the application within the specified service scope.

public abstract Task SeedData (IServiceScope scope, CancellationToken cancellationToken);

The SeedData method is an abstract lifecycle hook designed to be overridden in derived classes to implement custom data seeding logic. It is automatically invoked during application startup after migrations are successfully applied, ensuring that any mandatory baseline data (e.g., default admin users, lookup tables, static system configurations) is present in the data store.

Because it passes an IServiceScope, you can safely resolve scoped services (like an Entity Framework DbContext) directly within your implementation.

using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; public class AppDbInitializer(ILogger<AppDbInitializer> logger) : DbInitializer<AppDbContext>(logger) { public override async Task SeedData(IServiceScope scope, CancellationToken cancellationToken) { // Your seed service } }

MariaDB Notes

Pomelo auto-detects whether the server is MySQL or MariaDB based on the server version. If you need to pin the version:

// Pinning server version explicitly (advanced) // This is handled internally by Forge — no action needed for standard setups.

MariaDB and MySQL are wire-compatible for most EF Core operations. The same Forge.Repository.MySql package works for both. If you encounter dialect-specific issues, open an issue on the Forge.Repository issue tracker .