All the approaches I've found about declaring default values, generates the default value in the Sql script, not in the migration code.
My favorite is using attributes: 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; }
}
modelBuilder.Conventions.Add( new AttributeToColumnAnnotationConvention<SqlDefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.Single().DefaultValue));
And then customizing the SqlGenerator. But I don't like this because I don't see when generating the migration if everything it's as I wanted.
To do so, I modified the MigrationCodeGenerator like this: https://stackoverflow.com/a/21024108
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);
}
}
But in the method ScaffoldedMigration I cannot get my custom annotation SqlDefaultValue or any other annotation.
Is it possible to get this annotation?
You haven't indicated how you registered your ExtendedMigrationCodeGenerator
to be used, you can do this in the constructor of the Configuration
class in Configuration.cs
for example:
public Configuration()
{
AutomaticMigrationsEnabled = false;
AutomaticMigrationDataLossAllowed = false;
// Register the Customized Migration Generator to use
CodeGenerator = new ExtendedMigrationCodeGenerator();
}
But also do not forget the AlterColumnOperation
which might be your biggest issue if you are applying this to an existing schema.
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;
}
}
The other scenario where you will not see a generated output is if the convention and annotations were already applied in a previous migration that was generated before you configured the custom ExtendedMigrationCodeGenerator
.
Debugging custom migration logic isn't as simple as setting a breakpoint, because it is normally executed by external processes like Migration.exe
. So before breakpoints will work, we need to invoke the debugger, we can do this by inserting the following code either at the point where you want to debug or in the constructor of the migration code generator class:
if (!System.Diagnostics.Debugger.IsAttached)
System.Diagnostics.Debugger.Launch();
It is better to attach in a constructor rather than near the code you want to debug because we know the constructor should be executed under normal conditions, but the reason your code isn't working might be due to the method or code branch not being executed at all, if it's not being executed, then the
Launch()
command also will not be executed.
If you use this method to debug the migration and you don't get the debug attach dialog then either there are no migrations detected, or your ExtendedMigrationCodeGenerator
hasn't been registered correctly.