efx new Product: One Command to Scaffold EF Core & Apply Migrations

Aperta
#39,569 9 commenti 9 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 2 giorni

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
5/5
Tempo stimato
Più di una settimana
Idoneità per principianti
35/100
Tipo di issue
Funzionalità
Chiarezza
Abbastanza chiara
Stato di attività
Attiva
Stack tecnologico
csharp

Direzione di ricerca

Start by reading the EF Core CLI and migration tooling documentation to identify the existing command entry points; the issue does not name files or tests. Determine whether model scaffolding and combined migration execution fit the CLI's scope, then discuss the proposed command behavior with maintainers. Done means the supported command behavior and scope are agreed before implementation.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

customer-reported
WhatsApp Image 2026-11-12 at 9 48 34 AM (1)

EFX: Scaffold EF Core Entities and Apply Migrations in One Command

Every time I add a new entity in EF Core, I end up repeating the exact same boilerplate routine:

  1. Create a new .cs file in the Entities folder.
  2. Add the class and a primary key.
  3. Open DbContext and wire up a new DbSet<T>.
  4. Run dotnet ef migrations add ...
  5. Run dotnet ef database update
    None of these steps are hard, they're just repetitive friction—especially during early prototyping when the schema changes every ten minutes.
    To speed this up, I built a small .NET global tool prototype called EFX to collapse the whole workflow into a single command:
efx new Product

What it does under the hood

When you run the command from your project directory, it:

  • Creates an Entities/ folder (if missing) and generates Product.cs with a default Id.
  • Locates AppDbContext.cs and injects public DbSet<Product> Products => Set<Product>();.
  • Shells out to dotnet ef migrations add AddProduct.
  • Runs dotnet ef database update immediately after.

Project Setup

It's a single-file console app packed as a standard .NET tool.

EFX/
├── EFX.csproj
└── Program.cs

EFX.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <PackAsTool>true</PackAsTool>
    <ToolCommandName>efx</ToolCommandName>
    <PackageId>EFX.Tool</PackageId>
    <Version>1.0.0</Version>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

Program.cs

using System.Diagnostics;

const string marker = "// <EFX-DBSETS>";

if (args.Length < 2 || args[0] != "new")
{
    Console.WriteLine("Usage: efx new <EntityName>");
    return;
}

var entityName = args[1];
var contextName = "AppDbContext";

var contextPath = Directory
    .GetFiles(".", $"{contextName}.cs", SearchOption.AllDirectories)
    .FirstOrDefault(p =>
        !p.Contains($"{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}") &&
        !p.Contains($"{Path.DirectorySeparatorChar}obj{Path.DirectorySeparatorChar}"));

if (contextPath is null)
{
    Console.WriteLine("DbContext file was not found.");
    return;
}

var entitiesDirectory = Path.Combine(".", "Entities");
Directory.CreateDirectory(entitiesDirectory);

var entityPath = Path.Combine(entitiesDirectory, $"{entityName}.cs");

if (File.Exists(entityPath))
{
    Console.WriteLine("Entity already exists.");
    return;
}

// 1. Generate the entity
var entityCode = $"""
namespace App.Entities;

public class {entityName}
{{
    public int Id {{ get; set; }}
}}
""";

await File.WriteAllTextAsync(entityPath, entityCode);
Console.WriteLine($"Created: {entityPath}");

// 2. Register the DbSet
var contextCode = await File.ReadAllTextAsync(contextPath);

if (!contextCode.Contains(marker))
{
    Console.WriteLine($"Add the marker {marker} inside your DbContext first.");
    File.Delete(entityPath);
    return;
}

if (!contextCode.Contains("using App.Entities;"))
{
    contextCode = "using App.Entities;\n" + contextCode;
}

var dbSetCode = $"public DbSet<{entityName}> {entityName}s => Set<{entityName}>();";
contextCode = contextCode.Replace(marker, $"{dbSetCode}\n    {marker}");

await File.WriteAllTextAsync(contextPath, contextCode);
Console.WriteLine($"Registered DbSet<{entityName}>");

// 3. Create and apply migration
var migrationName = $"Add{entityName}";

if (await RunCommand("dotnet", "ef", "migrations", "add", migrationName) != 0)
{
    Console.WriteLine("Migration creation failed.");
    return;
}

if (await RunCommand("dotnet", "ef", "database", "update") != 0)
{
    Console.WriteLine("Database update failed. Check the generated migration.");
    return;
}

Console.WriteLine($"Successfully created {entityName} and updated the database.");

static async Task<int> RunCommand(string file, params string[] arguments)
{
    var startInfo = new ProcessStartInfo(file)
    {
        UseShellExecute = false
    };

    foreach (var argument in arguments)
        startInfo.ArgumentList.Add(argument);

    using var process = Process.Start(startInfo);
    if (process is null) return -1;

    await process.WaitForExitAsync();
    return process.ExitCode;
}


DbContext Setup

Right now, it relies on a simple comment marker to know where to drop the new DbSet. Just add // <EFX-DBSETS> inside your context class:

using Microsoft.EntityFrameworkCore;
using App.Entities;

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> o
Lingua principale
C#
Stelle
14.8k
Fork
3.4k
Merge medio
3g 18h
PR unite (30g)
159

Preparare l'ambiente

Apri in Codespaces

Avvia il container di sviluppo del progetto nel browser, con il tuo account GitHub.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di dotnet/efcore

Tutte le issue di dotnet/efcore

Issue simili

Altre issue su C#

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.