簡體   English   中英

如何在EF Core中添加自定義添加遷移行為?

[英]How to add custom Add-Migration behaviour in EF Core?

我的目標是創建一個自定義Attribute並允許。 Add-Migration以根據它生成自定義代碼。

Model和Attribute

public class MyAttribute: Attribute {}

public class MyModel
{
    public int Id { get; set; }

    [MyAttribute]
    public string Name { get; set; }
}

MigrationProviderAnnotationProvider

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

提前致謝!

問題是只有在將新列添加到現有表時才會調用AddColumnOperation方法。

對於CreateTable您需要覆蓋void Generate(CreateTableOperation operation, IModel model, MigrationCommandListBuilder builder)方法。 CreateTableOperation包含相同AddColumnOperation類型的Operations屬性。

這是一個完整的例子

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")
    }
}

希望這可以幫助!

IMigrationsSqlGenerator只能處理已生成的MigrationOperation 要檢測新Attribute更改,您可能需要替換IMigrationsModelDiffer服務。 然后,您可以返回一個新的SqlOperation(或自定義類型)以及兩個模型之間的其他差異。

從好的方面來說,這意味着您也可以在Down過程中生成撤消操作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM