我的目标是创建一个自定义的Attribute
并允许。Add-Migration
可以基于它生成自定义代码。
模型和Attribute
类
public class MyAttribute: Attribute {}
public class MyModel
{
public int Id { get; set; }
[MyAttribute]
public string Name { get; set; }
}
MigrationProvider
和AnnotationProvider
internal class MyMigrationsAnnotationProvider : SqliteMigrationsAnnotationProvider
{
public override IEnumerable<IAnnotation> For( IProperty property )
{
MemberInfo MInfo = property.PropertyInfo ?? ( MemberInfo ) property.FieldInfo;
MyAttribute MyAttr = MInfo?.GetCustomAttribute<MyAttribute>();
if ( MyAttr != null )
{
return base.For( property ).Concat( new IAnnotation[] { new Annotation( "MyAttribute", true ) } );
}
return base.For( property );
}
}
internal class MyMigrationsSqlGenerator : SqliteMigrationsSqlGenerator
{
public MyMigrationsSqlGenerator( IRelationalCommandBuilderFactory IRFactory, ISqlGenerationHelper ISHelper, IRelationalTypeMapper Mapper, IRelationalAnnotationProvider AnProvider )
: base( IRFactory, ISHelper, Mapper, AnProvider ) {}
protected override void Generate( AddColumnOperation operation, IModel model, MigrationCommandListBuilder builder )
{
throw new Exception( "Hello world" );
// Here's where I got it wrong.
// I thought I should be able to read the "MyAttribute" annotation from here and generate extra code in the Up method
/*
if( operation.FindAnnotation( "MyAttribute" ) != null )
{
builder.AppendLine( "Hello there, not sure if this would work." );
}
*/
}
}
class MyContext : DbContext
{
public DbSet<MyModel> MModel { get; set; }
protected override void OnConfiguring( DbContextOptionsBuilder optionsBuilder )
{
optionsBuilder.UseSqlite( "Data Source=mydata.db" );
optionsBuilder.ReplaceService<IMigrationsSqlGenerator, MyMigrationsSqlGenerator>();
optionsBuilder.ReplaceService<IMigrationsAnnotationProvider, MyMigrationsAnnotationProvider>();
}
}
生成的迁移代码(经过一些清理)
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "MyModel",
columns: table => new
{
Id = table.Column<string>(nullable: false),
Name = table.Column<string>(nullable: false)
.Annotation("MyAttribute", true),
});
// The following line is what I want it to be generated
migrationBuilder.Sql( "I WANT MY CUSTOM QUERY BE GENERATED HERE" );
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable( name: "MyModel" );
// The following line is what I want it to be generated
migrationBuilder.Sql( "I WANT MY CUSTOM QUERY BE GENERATED HERE" );
}
如您所见,MyAttribute
注释已成功添加到Up
方法中。但是,我似乎不能覆盖Generate
方法,因为在运行Add-Migration
时不会抛出Hello world
异常。
我正在使用EF Core 1.1.5
提前感谢!
发布于 2018-09-17 08:59:43
IMigrationsSqlGenerator
只能处理已生成的MigrationOperation
。要检测新Attribute
中的更改,可能需要替换IMigrationsModelDiffer
服务。然后,您可以返回一个新的SqlOperation (或自定义类型),其中包含两个模型之间的其他差异。
从好的方面来说,这意味着你也可以在Down过程中生成撤销操作。
发布于 2018-06-25 01:12:30
问题是,只有在向现有表中添加新列时才会调用AddColumnOperation
方法。
对于CreateTable
,您需要重写void Generate(CreateTableOperation operation, IModel model, MigrationCommandListBuilder builder)
方法。CreateTableOperation
包含相同AddColumnOperation
类型的操作属性。
下面是一个完整的示例
protected override void Generate(CreateTableOperation operation, IModel model, MigrationCommandListBuilder builder)
{
base.Generate(operation, model, builder);
foreach (var columnOperation in operation.Columns) //columnOperation is AddColumnOperation
{
//operation.FindAnnotation("MyAttribute")
}
}
希望这能有所帮助!
https://stackoverflow.com/questions/47879435
复制相似问题