C# 如何在Windows服务中使用EF核心迁移?
您好,我正在尝试实现一个需要EF核心迁移的Windows服务。以下是我的DbContext继承器:C# 如何在Windows服务中使用EF核心迁移?,c#,entity-framework,.net-core,entity-framework-core,windows-services,C#,Entity Framework,.net Core,Entity Framework Core,Windows Services,您好,我正在尝试实现一个需要EF核心迁移的Windows服务。以下是我的DbContext继承器: public sealed class ExchangeContext : DbContext { public const string SchemaName = "Exchange"; public ExchangeContext(DbContextOptions<ExchangeContext> options) :
public sealed class ExchangeContext : DbContext
{
public const string SchemaName = "Exchange";
public ExchangeContext(DbContextOptions<ExchangeContext> options)
: base(options)
{
}
...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
}
}
公共密封类ExchangeContext:DbContext
{
public const string SchemaName=“Exchange”;
公共ExchangeContext(DbContextOptions选项)
:基本(选项)
{
}
...
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
{
建模者
.ApplyConfigurationsFromAssembly(Assembly.getExecutionGassembly());
}
}
我的Program.cs文件如下所示:
public static class Program
{
public static void Main(string[] args) =>
Host
.CreateDefaultBuilder(args)
.ConfigureServices((_, services) =>
{
var configuration = services
.BuildServiceProvider()
.GetRequiredService<IConfiguration>();
services
.AddApplicationServices()
.AddInfrastructureServices(configuration);
})
.UseWindowsService()
.Build()
.Run();
}
公共静态类程序
{
公共静态void Main(字符串[]参数)=>
主办
.CreateDefaultBuilder(args)
.ConfigureServices((u,services)=>
{
var配置=服务
.BuildServiceProvider()
.GetRequiredService();
服务
.AddApplicationServices()
.AddInfrastructureServices(配置);
})
.UseWindowsService()
.Build()
.Run();
}
我使用以下逻辑注册DbContext:
...
.AddDatabaseContext<ExchangeContext>(
configuration,
DatabaseProvider.SqlServer,
false,
ExchangeContextConnectionStringSectionKey,
Assembly.GetExecutingAssembly().FullName)
...
namespace AsCore.Infrastructure.Persistence.EntityFrameworkCore
{
public static class EntityFrameworkCoreConfiguration
{
private const string SqlServerTag = "SqlServerConnection";
private const string PostgreSQLTag = "PostgreSQLConnection";
public static IServiceCollection AddDatabaseContext<TContext>(this IServiceCollection services,
IConfiguration configuration,
DatabaseProvider provider,
bool useHealthCheck,
string connectionStringSectionName,
string migrationAssemblyName = null) where TContext : DbContext
{
var connectionString = configuration
.GetConnectionString(connectionStringSectionName);
var databaseContextOptionsAction = CreateContextOptions(provider,
connectionString,
migrationAssemblyName);
return services
.AddDbContext<TContext>(databaseContextOptionsAction)
.ConfigureHealthChecks<TContext>(useHealthCheck,
provider,
connectionString);
}
public static IApplicationBuilder UseMigrationsOfContext<TContext>(this IApplicationBuilder applicationBuilder)
where TContext : DbContext
{
using var serviceScope = applicationBuilder
.ApplicationServices
.CreateScope();
var databaseContext = serviceScope
.ServiceProvider
.GetService<TContext>();
var isInvalid = databaseContext is null;
if (isInvalid)
{
var errorMessage =
$"{nameof(UseMigrationsOfContext)}: {typeof(TContext).FullName}";
throw new ArgumentException(errorMessage);
}
databaseContext
.Database
.Migrate();
return applicationBuilder;
}
private static Action<DbContextOptionsBuilder> CreateContextOptions(DatabaseProvider provider,
string connectionString,
string migrationAssemblyName = null) =>
provider switch
{
DatabaseProvider.SqlServer => migrationAssemblyName != null
? (Action<DbContextOptionsBuilder>) (optionsBuilder => optionsBuilder
.UseSqlServer(connectionString,
sqlServerOptionsBuilder =>
sqlServerOptionsBuilder.MigrationsAssembly(migrationAssemblyName)))
: (DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseSqlServer(connectionString),
DatabaseProvider.PostgreSQL => migrationAssemblyName != null
? (Action<DbContextOptionsBuilder>) (optionsBuilder => optionsBuilder
.UseNpgsql(connectionString,
postgresOptionsBuilder =>
postgresOptionsBuilder.MigrationsAssembly(migrationAssemblyName)))
: (DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseNpgsql(connectionString),
_ => throw new ArgumentOutOfRangeException(nameof(DatabaseProvider))
};
private static IServiceCollection ConfigureHealthChecks<TContext>(this IServiceCollection services,
bool useHealthCheck,
DatabaseProvider provider,
string connectionString) where TContext : DbContext
{
if (!useHealthCheck)
{
return services;
}
return services
.AddDatabaseHealthChecks<TContext>(
provider,
connectionString);
}
private static IServiceCollection AddDatabaseHealthChecks<TContext>(this IServiceCollection services,
DatabaseProvider provider,
string connectionString) where TContext : DbContext =>
provider switch
{
DatabaseProvider.SqlServer => services
.AddHealthChecks()
.AddSqlServer(connectionString,
name: typeof(TContext).FullName,
tags: new[] { SqlServerTag })
.Services,
DatabaseProvider.PostgreSQL => services
.AddHealthChecks()
.AddNpgSql(connectionString,
name: typeof(TContext).FullName,
tags: new[] { PostgreSQLTag })
.Services,
_ => throw new ArgumentOutOfRangeException(nameof(DatabaseProvider))
};
}
}
。。。
.AddDatabaseContext(
配置
DatabaseProvider.SqlServer,
假,,
ExchangeContextConnectionStringSectionKey,
Assembly.GetExecutionGassembly().FullName)
...
命名空间AsCore.Infrastructure.Persistence.EntityFrameworkCore
{
公共静态类EntityFrameworkCoreConfiguration
{
私有常量字符串SqlServerTag=“SqlServerConnection”;
私有常量字符串PostgreSQLTag=“PostgreSQLConnection”;
公共静态IServiceCollection AddDatabaseContext(此IServiceCollection服务,
i配置配置,
数据库提供者,
布尔使用健康检查,
字符串连接StringSectionName,
字符串migrationAssemblyName=null),其中TContext:DbContext
{
var connectionString=配置
.GetConnectionString(ConnectionString部分名称);
var DatabaseContextOptions操作=CreateContextOptions(提供程序,
连接字符串,
迁移组装名称);
回程服务
.AddDbContext(DatabaseContextOptions操作)
.配置HealthChecks(使用HealthCheck,
供应商,
连接字符串);
}
公共静态IApplicationBuilder使用上下文迁移(此IApplicationBuilder应用程序生成器)
其中TContext:DbContext
{
使用var serviceScope=applicationBuilder
.应用程序服务
.CreateScope();
var-databaseContext=serviceScope
.服务提供者
.GetService();
var isInvalid=数据库上下文为空;
如果(isInvalid)
{
var错误消息=
$“{nameof(UseMigrationsOfContext)}:{typeof(TContext.FullName}”;
抛出新的ArgumentException(errorMessage);
}
数据库上下文
数据库
.Migrate();
返回applicationBuilder;
}
专用静态操作CreateContextOptions(数据库提供程序,
字符串连接字符串,
字符串迁移AssemblyName=null)=>
提供者交换机
{
DatabaseProvider.SqlServer=>migrationAssemblyName!=null
?(操作)(选项生成器=>选项生成器
.UseSqlServer(连接字符串,
sqlServerOptionsBuilder=>
sqlServerOptionsBuilder.MigrationsAssembly(migrationAssemblyName)))
:(DBContextOptions Builder Options Builder)=>Options Builder.UseSqlServer(connectionString),
DatabaseProvider.PostgreSQL=>migrationAssemblyName!=null
?(操作)(选项生成器=>选项生成器
.UseNpgsql(连接字符串,
postgresOptionsBuilder=>
postgresOptionsBuilder.migrationassembly(migrationAssemblyName)))
:(DBContextOptions Builder Options Builder)=>Options Builder.UseNpgsql(connectionString),
_=>抛出新ArgumentOutOfRangeException(nameof(DatabaseProvider))
};
专用静态IServiceCollection配置HealthChecks(此IServiceCollection服务,
布尔使用健康检查,
数据库提供者,
字符串连接字符串),其中TContext:DbContext
{
如果(!useHealthCheck)
{
返回服务;
}
回程服务
.AddDatabaseHealthChecks(
供应商,
连接字符串);
}
专用静态IServiceCollection AddDatabaseHealthChecks(此IServiceCollection服务,
数据库提供者,
字符串连接字符串),其中TContext:DbContext=>
提供者交换机
{
DatabaseProvider.SqlServer=>services
.AddHealthChecks()
.AddSqlServer(连接字符串,
名称:typeof(TContext).FullName,
标记:新[]{SqlServerTag})
.服务,
DatabaseProvider.PostgreSQL=>services
.AddHealthChecks()
.AddNpgSql(连接字符串,
N
public class ExchangeContextFactory : IDesignTimeDbContextFactory<ExchangeContext>
{
public ExchangeContext CreateDbContext(string[] args)
{
var appSettingsPath = Path.Combine(Directory.GetCurrentDirectory(), "relative-path-to-your-appsettings-file");
var configuration = new ConfigurationBuilder()
.SetBasePath(appSettingsPath)
.AddJsonFile("appsettings.json")
.Build();
var builder = new DbContextOptionsBuilder<ExchangeContext>();
builder.UseSqlServer(
configuration
.GetConnectionString("SqlServer") // In your case, the section referring to "ExchangeContextConnectionStringSectionKey"
);
return new ExchangeContext(builder.Options);
}
}
dotnet ef migrations add InitialCreate --context ExchangeContext --project ExchangeContextProjectName