![](/img/trans.png)
[英]EF Core migration error: PositionalParameterNotFound,Add-Migration
[英]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; }
}
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
提前致謝!
問題是只有在將新列添加到現有表時才會調用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.