Entity Framework 6 Code first 覆盖 MigrationCodeGenerator 的默认值

Ale*_*lex 5 entity-framework default-value ef-code-first entity-framework-6 entity-framework-migrations

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

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

[SqlDefaultValue(DefaultValue = "getutcdate()")]
public DateTime CreatedDateUtc { get; set; }
Run Code Online (Sandbox Code Playgroud)

属性定义

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

在上下文的“OnModelCreating”中添加

modelBuilder.Conventions.Add( new AttributeToColumnAnnotationConvention<SqlDefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.Single().DefaultValue));
Run Code Online (Sandbox Code Playgroud)

然后自定义SqlGenerator。但我不喜欢这样,因为我不知道在生成迁移时是否一切都如我所愿。

为此,我像这样修改了MigrationCodeGeneratorhttps : //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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

有没有可能得到这个注解?

Chr*_*ler 0

您还没有表明如何注册要使用的,您可以在类ExtendedMigrationCodeGenerator的构造函数中执行此操作,例如:ConfigurationConfiguration.cs

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

但也不要忘记,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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

调试提示:

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

if (!System.Diagnostics.Debugger.IsAttached)
    System.Diagnostics.Debugger.Launch();
Run Code Online (Sandbox Code Playgroud)

最好附加在构造函数中,而不是附加在要调试的代码附近,因为我们知道构造函数应该在正常情况下执行,但代码不工作的原因可能是由于方法或代码分支未执行无论如何,如果它没有被执行,那么该Launch()命令也不会被执行。

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