efx new Product: One Command to Scaffold EF Core & Apply Migrations
Los mantenedores suelen responder en 2 días
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 35/100
- Tipo de issue
- Nueva funcionalidad
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- csharp
- Área
- cli, developer-experience
Línea de trabajo
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.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
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:
- Create a new
.csfile in theEntitiesfolder. - Add the class and a primary key.
- Open
DbContextand wire up a newDbSet<T>. - Run
dotnet ef migrations add ... - 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 generatesProduct.cswith a defaultId. - Locates
AppDbContext.csand injectspublic DbSet<Product> Products => Set<Product>();. - Shells out to
dotnet ef migrations add AddProduct. - Runs
dotnet ef database updateimmediately 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
- Lenguaje dominante
- C#
- Estrellas
- 14.8k
- Forks
- 3.4k
- Merge medio
- 3 d 18 h
- PR fusionados (30 d)
- 159
Preparar el entorno
Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de dotnet/efcore
-
customer-reported
Dificultad 4/5 3-5 días Aptitud para principiantes 54/100
Los mantenedores suelen responder en 2 días
-
Dificultad 4/5 3-5 días Aptitud para principiantes 48/100
Los mantenedores suelen responder en 2 días
-
Dificultad 4/5 3-5 días Aptitud para principiantes 48/100
Los mantenedores suelen responder en 2 días
-
Regression in 11.0: replacing an owned instance or re-adding an entity with the same key sets unchanged OnAdd properties to nullPosiblemente ocupada @seragAhmed la tomó hoy. Abierto
Dificultad 4/5 3-5 días Aptitud para principiantes 48/100
dotnet/efcore#39617 · 1 comentario ·
Los mantenedores suelen responder en 2 días
-
customer-reported
Dificultad 4/5 3-5 días Aptitud para principiantes 48/100
Los mantenedores suelen responder en 2 días
Todos los issues de dotnet/efcore
Issues similares
-
bug emitter:client:csharp
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
microsoft/typespec#12572 · 1 comentario · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
needs-area-label
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 2 días
-
AWS Lambda: KeyNotFoundException drops HTTP-triggered transactions when allowAllHeaders is disabledAbiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
newrelic/newrelic-dotnet-agent#3949 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
area-networking
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
dotnet/aspnetcore#70545 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 87/100
Los mantenedores suelen responder en 1 día