Uso de un proyecto de migraciones independientes

Puede almacenar migraciones en un proyecto diferente del que contiene DbContext. Esto se recomienda cuando el proyecto de aplicación es específico de la plataforma, como WinUI, .NET MAUI, Blazor WebAssembly o Azure Functions, o cuando tiene como destino un identificador de tiempo de ejecución específico (RID). También se puede usar para mantener más de un conjunto de migraciones.

Diseño del proyecto

En el ejemplo se usan tres proyectos:

Proyecto Responsabilidad References
WebApplication1.Data Posee los DbContext tipos de entidad y Proveedor de EF Core
WebApplication1.Migrations Posee migraciones, la instantánea del modelo y la creación de contextos en tiempo de diseño. Proyecto de datos, proveedor de EF Core y Microsoft.EntityFrameworkCore.Design
WebApplication1 Ejecuta la aplicación Proyecto de datos y proyecto de migraciones

La aplicación necesita una referencia al proyecto de migraciones cuando detecta o aplica migraciones en tiempo de ejecución, por ejemplo llamando a Migrate. Si las migraciones solo se aplican mediante un artefacto de implementación y la aplicación nunca las carga, esa referencia no es necesaria.

Configuración de los proyectos

  1. Cree una biblioteca de clases para las migraciones y agregue una referencia al proyecto que contiene .DbContext

  2. Agregue el proveedor de base de datos y Microsoft.EntityFrameworkCore.Design al proyecto de migraciones. Marque el paquete de diseño como una dependencia de desarrollo privada:

    <ItemGroup>
      <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="...">
        <PrivateAssets>all</PrivateAssets>
        <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      </PackageReference>
      <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="..." />
    </ItemGroup>
    
    <ItemGroup>
      <ProjectReference Include="..\WebApplication1.Data\WebApplication1.Data.csproj" />
    </ItemGroup>
    
  3. Implemente IDesignTimeDbContextFactory<TContext> en el proyecto de migraciones. La factoría permite que las herramientas creen el contexto sin ejecutar el proyecto de aplicación:

    public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
    {
        public ApplicationDbContext CreateDbContext(string[] args)
        {
            var connectionString = args.FirstOrDefault()
                ?? @"Server=(localdb)\mssqllocaldb;Database=WebApplication1;Trusted_Connection=True";
    
            var options = new DbContextOptionsBuilder<ApplicationDbContext>()
                .UseSqlServer(
                    connectionString,
                    sqlServer => sqlServer.MigrationsAssembly(typeof(ApplicationDbContextFactory).Assembly.GetName().Name))
                .Options;
    
            return new ApplicationDbContext(options);
        }
    }
    

    Mantenga la configuración del modelo y el proveedor en tiempo de diseño coherentes con la configuración del entorno de ejecución. El ejemplo acepta un argumento opcional cadena de conexión y usa una conexión de desarrollo local cuando no se proporciona ningún argumento.

  4. Configure el ensamblado de migraciones al registrar el contexto en tiempo de ejecución:

    services.AddDbContext<ApplicationDbContext>(
        options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection"),
                x => x.MigrationsAssembly("WebApplication1.Migrations")));
    
  5. Si la aplicación aplica migraciones o las detecta en tiempo de ejecución, agregue una referencia normal desde la aplicación al proyecto de migraciones:

    <ItemGroup>
      <ProjectReference Include="..\WebApplication1.Migrations\WebApplication1.Migrations.csproj" />
    </ItemGroup>
    

    El proyecto de datos no debe hacer referencia al proyecto de migraciones. Esto crearía una dependencia circular porque el proyecto de migraciones ya hace referencia al proyecto de datos.

  6. Si ya existen migraciones, mueva todos los archivos de migración y la instantánea del modelo al proyecto de migraciones y actualice sus espacios de nombres. Cuando no hay migraciones existentes, el generador en tiempo de diseño permite crear la migración inicial directamente en el proyecto de migraciones.

Uso de las herramientas

Use el proyecto de migraciones como proyecto de destino y proyecto de inicio. El proyecto de destino recibe archivos generados, mientras que el proyecto de inicio se compila y ejecuta mediante las herramientas. En este diseño, el uso del proyecto de migraciones para ambos impide que las herramientas ejecuten el código de inicio de la aplicación.

Ejecute estos comandos desde el directorio de la solución:

dotnet ef migrations add NewMigration \
    --project WebApplication1.Migrations \
    --startup-project WebApplication1.Migrations

Las mismas opciones de proyecto se aplican a otros comandos:

dotnet ef migrations list \
    --project WebApplication1.Migrations \
    --startup-project WebApplication1.Migrations

dotnet ef migrations script --output artifacts/migrations.sql \
    --project WebApplication1.Migrations \
    --startup-project WebApplication1.Migrations

dotnet ef migrations bundle --output artifacts/efbundle \
    --project WebApplication1.Migrations \
    --startup-project WebApplication1.Migrations

A partir de EF Core 11, las opciones de proyecto repetidas se pueden almacenar en .config/dotnet-ef.json.

Compile el proyecto de migraciones antes de ejecutar comandos con --no-buildo antes de que otro proceso consuma su salida. Un comando normal dotnet ef compila automáticamente los proyectos de destino e inicio.

Aplicaciones específicas de la plataforma

No use un proyecto de aplicación específico de la plataforma como proyecto de inicio para las herramientas de EF. Los proyectos móviles, de explorador, de escritorio, de función y específicos de RID pueden requerir una carga de trabajo o un host nativo que dotnet ef no se pueda ejecutar. A partir de EF Core 11, las herramientas advierten cuando se usa un proyecto de inicio específico de la plataforma.

Use el diseño descrito anteriormente para .NET MAUI, WinUI, Blazor WebAssembly, Azure Functions y aplicaciones similares:

  1. Coloque los tipos de contexto y entidad en un proyecto de datos compartido.
  2. Coloque las migraciones y IDesignTimeDbContextFactory<TContext> en un proyecto de .NET multiplataforma normal.
  3. Ejecute las herramientas con el proyecto de migraciones como proyecto de destino e inicio.
  4. Haga referencia al proyecto de migraciones desde la aplicación solo si la aplicación carga o aplica migraciones en tiempo de ejecución.

No está planeada la compatibilidad con herramientas directas para proyectos de plataforma Xamarin y MAUI; consulte dotnet/efcore#7152. Xamarin las aplicaciones deben actualizarse primero a .NET MAUI.

Arquitectura de procesos

El proceso que ejecuta las herramientas debe poder cargar cada ensamblado en tiempo de diseño. Un proceso de Visual Studio o .NET de 64 bits no puede cargar un ensamblado de inicio de solo x86 y la misma restricción se aplica a Arm64 y otras arquitecturas. Se prefiere un proyecto de migraciones de AnyCPU. Si las dependencias en tiempo de diseño requieren una arquitectura específica, invoque explícitamente un SDK de .NET coincidente.

La arquitectura del proceso en tiempo de diseño es independiente del destino de implementación. Al crear una agrupación, use --target-runtime o -TargetRuntime para generar un artefacto para el RID de implementación, como linux-arm64 o osx-arm64.