Skip to content

Instantly share code, notes, and snippets.

@rkttu
Created October 17, 2024 02:09
Show Gist options
  • Save rkttu/1fc5a0ec68bb6939ef1738e2ccf8cf73 to your computer and use it in GitHub Desktop.
Save rkttu/1fc5a0ec68bb6939ef1738e2ccf8cf73 to your computer and use it in GitHub Desktop.
How to generate SQL DDL compatible with the entire model instead of auto-migration
// Package Required: Microsoft.EntityFrameworkCore.Relational
// In this example, I am using the EF Core driver (Pomelo.EntityFrameworkCore.MySql) from the Pomelo Foundation Project to generate DDL for MariaDB.
// However, you can also use any other driver you want (Microsoft SQL Server, Sqlite, Oracle, etc.).
using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;
using Pomelo.EntityFrameworkCore.MySql;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
var generatedScript = EFCoreExtensions.GenerateDatabaseDefinitions<SampleDbContext>(
o => o.UseMySql(ServerVersion.Create(11, 5, 2, ServerType.MariaDb)));
Console.Out.WriteLine(generatedScript);
#region Sample Model
public record Users
{
[Key]
public required Guid Id { get; init; }
public required string Username { get; init; }
public required DateTime RegisteredDateTimeUtc { get; init; }
}
public class SampleDbContext : DbContext
{
public SampleDbContext(DbContextOptions<SampleDbContext> options) : base(options) { }
public DbSet<Users> Users { get; set; } = default!;
}
#endregion // Sample Model
internal static class EFCoreExtensions
{
public static string GenerateDatabaseDefinitions<TDbContext>(
Action<DbContextOptionsBuilder<TDbContext>> options)
where TDbContext : DbContext
{
var optionsBuilder = new DbContextOptionsBuilder<TDbContext>();
options.Invoke(optionsBuilder);
var dbContextType = typeof(TDbContext);
var publicConstructors = dbContextType.GetConstructors();
foreach (var eachConstructor in publicConstructors)
{
var parameters = eachConstructor.GetParameters();
if (parameters.Length != 1)
continue;
var singleParameter = parameters.First();
if (!singleParameter.ParameterType.IsGenericType)
continue;
var singleParameterTypedef = singleParameter.ParameterType.GetGenericTypeDefinition();
if (singleParameterTypedef != typeof(DbContextOptions<>))
continue;
var singleParameterTypeArgs = singleParameter.ParameterType.GetGenericArguments();
if (singleParameterTypeArgs.Length != 1)
continue;
var singleParameterSingleTypeArg = singleParameterTypeArgs.First();
if (singleParameterSingleTypeArg != dbContextType)
continue;
using var context = eachConstructor.Invoke(new object[] { optionsBuilder.Options }) as TDbContext;
if (context == null)
continue;
return context.Database.GenerateCreateScript();
}
throw new NotSupportedException($"No supported public constructors for '{typeof(TDbContext)}' type.");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment