目录
背景
更改表名称和架构
更改列名称
添加具有默认值的列
添加必填列
关于代码示例
引用
背景
实体框架核心通过在名为__EFMigrationsHistory和架构dbo的表中添加日志来跟踪应用的迁移。迁移表包含两列MigrationId和ProductVersion。在这里,我们将探索一些自定义此表的选项。
- 更改迁移表名称和架构
- 更改迁移表的列名
- 在迁移表中添加默认值列
- 在迁移表中添加必填列
更改表名称和架构
我们将对迁移表使用自定义表名称__Migrations和模式名称track。模式名称是可选的,如果未指定,则默认为dbo。
public class AppDb : DbContext
{
public DbSet<Process> Process { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var config = new ConfigurationBuilder()
.AddJsonFile(Path.Combine(AppContext.BaseDirectory, "appsettings.json"),
optional: false, reloadOnChange: true)
.Build();
optionsBuilder
.UseSqlServer(config.GetConnectionString("DatabaseConnection"),
d => { d.MigrationsHistoryTable("__Migrations", "track"); });
}
}
更改列名称
要更改列名,我们将用自定义配置类HistoryRepository替换现有的/默认服务类型IHistoryRepository:
public class AppDb : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var config = new ConfigurationBuilder()
.AddJsonFile(Path.Combine(AppContext.BaseDirectory, "appsettings.json"),
optional: false, reloadOnChange: true)
.Build();
optionsBuilder
.UseSqlServer(config.GetConnectionString("DatabaseConnection")})
.ReplaceService<IHistoryRepository, HistoryRepository>();
}
}
在这里,我们将表列名称从:
- MigrationId到Id
- ProductVersion到Version。
internal class HistoryRepository : SqlServerHistoryRepository
{
public HistoryRepository(HistoryRepositoryDependencies dependencies) :
base(dependencies)
{
}
protected override void ConfigureTable(EntityTypeBuilder<HistoryRow> history)
{
base.ConfigureTable(history);
history.Property(h => h.MigrationId).HasColumnName("Id");
history.Property(h => h.ProductVersion).HasColumnName("Version");
}
}
在ConfigureTable(EntityTypeBuilder<HistoryRow> history)方法中,此部分实际上看起来更小,就像使用Fluent API的实体映射一样。我们应该能够更改其他内容,例如表名、模式名称、数据类型等。我还没有尝试过,但从逻辑上讲,这应该有效。
添加具有默认值的列
向项目添加空迁移Init。请务必确保这是第一次迁移,并在将任何表或任何其他对象添加到DbContext类之前添加。最初,Up和Down方法将为空。
将新列AppliedAtUtc添加到迁移表[track].[__Migrations]中,并为该列创建约束DF__Migrations_AppliedAtUtc,以将当前UTC日期时间设置为默认值。
Down
删除我们在up部分和列本身中添加的约束。
public partial class Init : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("ALTER TABLE [track].[__Migrations]
ADD AppliedAtUtc DATETIME NULL;");
migrationBuilder.Sql("ALTER TABLE [track].[__Migrations]
ADD CONSTRAINT DF__Migrations_AppliedAtUtc
DEFAULT GETUTCDATE() FOR [AppliedAtUtc];");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropCheckConstraint("DF__Migrations_AppliedAtUtc",
"__Migrations", "track");
migrationBuilder.DropColumn("AppliedAtUtc", "__Migrations", "track");
}
}
等效的SQL:
/*changes*/
ALTER TABLE [track].[__Migrations] ADD CreatedON DATETIME NULL;
ALTER TABLE [track].[__Migrations] _
ADD CONSTRAINT DF__Migrations_CreatedON DEFAULT GETUTCDATE() FOR [CreatedON];
/*rollback*/
ALTER TABLE [track].[__Migrations] DROP CONSTRAINT DF__Migrations_CreatedON;
ALTER TABLE [track].[__Migrations] DROP COLUMN CreatedON;
添加必填列
在这里,我们将向迁移表添加一个必需列ProjectName。
public class AppDb : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var config = new ConfigurationBuilder()
.AddJsonFile(Path.Combine(AppContext.BaseDirectory,
"appsettings.json"), optional: false, reloadOnChange: true)
.Build();
optionsBuilder
.UseSqlServer(config.GetConnectionString("DatabaseConnection")})
.ReplaceService<IHistoryRepository, HistoryRepository>();
}
}
在ConfigureTable(EntityTypeBuilder<HistoryRow> history)里面,我们根据需要添加一个新列。在GetInsertScript(HistoryRow row)方法中,我们正在为迁移表创建自定义insert语句。
public class ContextConstants
{
public static string ProjectName = "Console";
}
internal class HistoryRepository : SqlServerHistoryRepository
{
public const string CustomColumnName = "ProjectName";
public HistoryRepository(HistoryRepositoryDependencies dependencies) :
base(dependencies)
{
}
protected override void ConfigureTable(EntityTypeBuilder<HistoryRow> history)
{
base.ConfigureTable(history);
history.Property<string>(CustomColumnName).HasMaxLength(300).IsRequired();
}
public override string GetInsertScript(HistoryRow row)
{
var stringTypeMapping =
Dependencies.TypeMappingSource.GetMapping(typeof(string));
return new StringBuilder()
.Append("INSERT INTO ")
.Append(SqlGenerationHelper.DelimitIdentifier(TableName, TableSchema))
.Append("(")
.Append(SqlGenerationHelper.DelimitIdentifier(MigrationIdColumnName))
.Append(", ")
.Append(SqlGenerationHelper.DelimitIdentifier(ProductVersionColumnName))
.Append(", ")
.Append(SqlGenerationHelper.DelimitIdentifier(CustomColumnName))
.Append(") ")
.Append("VALUES (")
.Append(stringTypeMapping.GenerateSqlLiteral(row.MigrationId))
.Append(", ")
.Append(stringTypeMapping.GenerateSqlLiteral(row.ProductVersion))
.Append(", ")
.Append(stringTypeMapping.GenerateSqlLiteral(ContextConstants.ProjectName))
.Append(")")
.AppendLine(SqlGenerationHelper.StatementTerminator)
.ToString();
}
}
关于代码示例
- Visual Studio 2022 Solution
- EF Core 6(也使用EF Core 5进行测试)
- 检查Db.Custom项目代码,AppDb.cs。为了进行测试,我们需要将此项目设置为启动项目。
在appsettings.json中,我们将找到目标数据库连接:
{
"ConnectionStrings": {
"DatabaseConnection": "Data Source=.\\SQLEXPRESS;Initial Catalog=Cup;
Integrated Security=True"
}
}
命令:
Add-Migration Init
Update-Database
Script-Migration
Drop-Database
Remove-Migration Init
db:
引用
- Custom Migrations History Table - EF Core | Microsoft Learn
- How to Customize Migration History Table with Entity Framework Core - Stack Overflow
https://www.codeproject.com/Articles/5338891/Customize-Entity-Framework-Core-Migration-History
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)