实体框架6代码优先覆盖MigrationCodeGenerator的默认值

时间:2018-03-18 00:56:34

标签: entity-framework entity-framework-6 ef-code-first default-value ef-migrations

我发现的有关声明默认值的所有方法都会在Sql脚本中生成默认值,而不是在迁移代码中生成。

我最喜欢的是使用属性:https://stackoverflow.com/a/34894274/132942

[SqlDefaultValue(DefaultValue = "getutcdate()")]
public DateTime CreatedDateUtc { get; set; }

属性定义

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class SqlDefaultValueAttribute : Attribute
{
    public string DefaultValue { get; set; }
}

在" OnModelCreating"添加

的上下文
modelBuilder.Conventions.Add( new AttributeToColumnAnnotationConvention<SqlDefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.Single().DefaultValue));

然后自定义 SqlGenerator 。但是我不喜欢这样,因为如果按照我想要的所有内容进行迁移,我就不会看到它。

为此,我修改了 MigrationCodeGenerator ,如下所示:https://stackoverflow.com/a/21024108

在自定义MigrationCodeGenerator

public class ExtendedMigrationCodeGenerator : MigrationCodeGenerator
{
    public override ScaffoldedMigration Generate(string migrationId, IEnumerable<MigrationOperation> operations, string sourceModel, string targetModel, string @namespace, string className)
    {
        foreach (MigrationOperation operation in operations)
        {
            if (operation is CreateTableOperation)
            {
                foreach (var column in ((CreateTableOperation)operation).Columns)
                {
                    System.Data.Entity.Infrastructure.Annotations.AnnotationValues values;
                    if (column.Annotations.TryGetValue("SqlDefaultValue", out values))
                    {
                        column.DefaultValueSql = (string)values.NewValue;
                    }
                }
            }
            else if (operation is AddColumnOperation)
            {
                ColumnModel column = ((AddColumnOperation)operation).Column;

                System.Data.Entity.Infrastructure.Annotations.AnnotationValues values;
                if (column.Annotations.TryGetValue("SqlDefaultValue", out values))
                {
                    column.DefaultValueSql = (string)values.NewValue;
                }

            }
        }

        CSharpMigrationCodeGenerator generator = new CSharpMigrationCodeGenerator();

        return generator.Generate(migrationId, operations, sourceModel, targetModel, @namespace, className);
    }
}

但是在方法 ScaffoldedMigration 中,我无法获取自定义注释 SqlDefaultValue 或任何其他注释。

是否可以获得此注释?

1 个答案:

答案 0 :(得分:0)

您尚未说明如何{em>注册要使用的ExtendedMigrationCodeGenerator,可以在Configuration中的Configuration.cs类的构造函数中进行以下操作:例如:

public Configuration()
{
    AutomaticMigrationsEnabled = false;
    AutomaticMigrationDataLossAllowed = false;
    // Register the Customized Migration Generator to use
    CodeGenerator = new ExtendedMigrationCodeGenerator();
}

但是也不要忘记AlterColumnOperation,如果将其应用于现有架构,这可能是最大的问题。

else if (operation is AlterColumnOperation alterColumnOp)
{
    ColumnModel column = alterColumnOp.Column;

    System.Data.Entity.Infrastructure.Annotations.AnnotationValues values;
    if (column.Annotations.TryGetValue("SqlDefaultValue", out values))
    {
        column.DefaultValueSql = (string)values.NewValue;
    }
}

您看不到生成的输出的另一种情况是,在配置自定义ExtendedMigrationCodeGenerator之前 之前,在先前的迁移中已经应用了约定和注释。 >

调试提示:

调试自定义迁移逻辑并不像设置断点那样简单,因为它通常由Migration.exe之类的外部进程执行。因此,在断点起作用之前,我们需要调用调试器,我们可以通过在要调试的位置或迁移代码生成器类的构造函数中插入以下代码来做到这一点:

if (!System.Diagnostics.Debugger.IsAttached)
    System.Diagnostics.Debugger.Launch();

最好将其附加在构造函数中,而不要附加在要调试的代码附近,因为我们知道该构造函数应在正常条件下执行,但是您的代码不起作用的原因可能是由于方法或代码分支引起的根本不执行,如果不执行,则Launch()命令也将不执行。

如果使用此方法调试迁移,但没有得到调试附加对话框,则可能是未检测到迁移,或者ExtendedMigrationCodeGenerator尚未正确注册。