protected override void ColumnDefinition( string schema, string table, string name, ColumnOperation operation, IModel model, MigrationCommandListBuilder builder) { Check.NotEmpty(name, nameof(name)); Check.NotNull(operation, nameof(operation)); Check.NotNull(builder, nameof(builder)); if (operation.ComputedColumnSql != null) { ComputedColumnDefinition(schema, table, name, operation, model, builder); return; } var columnType = GetColumnType(schema, table, name, operation, model); builder .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(name)) .Append(" ") .Append(columnType); builder.Append(operation.IsNullable ? " NULL" : " NOT NULL"); DefaultValue(operation.DefaultValue, operation.DefaultValueSql, columnType, builder); }
protected override string GetColumnType( [CanBeNull] string schema, [NotNull] string table, [NotNull] string name, [NotNull] ColumnOperation operation, [CanBeNull] IModel model) { var storeType = operation.ColumnType; if (IsIdentity(operation) && (storeType == null || Dependencies.TypeMappingSource.FindMapping(storeType) is JetIntTypeMapping)) { // This column represents the actual identity. storeType = "counter"; } else if (storeType != null && IsExplicitIdentityColumnType(storeType)) { // While this column uses an identity type (e.g. counter), it is not an actual identity column, because // it was not marked as one. storeType = "integer"; } storeType ??= base.GetColumnType(schema, table, name, operation, model); if (string.Equals(storeType, "counter", StringComparison.OrdinalIgnoreCase) && operation[JetAnnotationNames.Identity] is string identity && !string.IsNullOrEmpty(identity) && identity != "1, 1") { storeType += $"({identity})"; } return(storeType); }
/// <summary> /// Generates a SQL fragment for a column definition for the given column metadata. /// </summary> /// <param name="schema"> The schema that contains the table, or <see langword="null" /> to use the default schema. </param> /// <param name="table"> The table that contains the column. </param> /// <param name="name"> The column name. </param> /// <param name="operation"> The column metadata. </param> /// <param name="model"> The target model which may be <see langword="null" /> if the operations exist without a model. </param> /// <param name="builder"> The command builder to use to add the SQL fragment. </param> protected override void ColumnDefinition( string schema, string table, string name, ColumnOperation operation, IModel model, MigrationCommandListBuilder builder) { base.ColumnDefinition(schema, table, name, operation, model, builder); var inlinePk = operation[SqliteAnnotationNames.InlinePrimaryKey] as bool?; if (inlinePk == true) { var inlinePkName = operation[ SqliteAnnotationNames.InlinePrimaryKeyName] as string; if (!string.IsNullOrEmpty(inlinePkName)) { builder .Append(" CONSTRAINT ") .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(inlinePkName)); } builder.Append(" PRIMARY KEY"); var autoincrement = operation[SqliteAnnotationNames.Autoincrement] as bool? // NB: Migrations scaffolded with version 1.0.0 don't have the prefix. See #6461 ?? operation[SqliteAnnotationNames.LegacyAutoincrement] as bool?; if (autoincrement == true) { builder.Append(" AUTOINCREMENT"); } } }
private void Initialize( ColumnOperation columnOperation, IProperty property, Type clrType, bool isNullable, IEnumerable <IAnnotation> migrationsAnnotations, bool inline = false, IEntityType userDefinedType = null) { columnOperation.ClrType = clrType; columnOperation.ColumnType = userDefinedType != null?userDefinedType.GetTableName() : property.GetConfiguredColumnType(); columnOperation.MaxLength = property.GetMaxLength(); columnOperation.IsUnicode = property.IsUnicode(); columnOperation.IsFixedLength = property.IsFixedLength(); columnOperation.IsRowVersion = property.ClrType == typeof(byte[]) && property.IsConcurrencyToken && property.ValueGenerated == ValueGenerated.OnAddOrUpdate; columnOperation.IsNullable = isNullable; var defaultValue = userDefinedType != null ? null : GetDefaultValue(property); columnOperation.DefaultValue = (defaultValue == DBNull.Value ? null : defaultValue) ?? (inline || isNullable ? null : userDefinedType != null ? null : GetDefaultValue(columnOperation.ClrType)); columnOperation.DefaultValueSql = property.GetDefaultValueSql(); columnOperation.ComputedColumnSql = property.GetComputedColumnSql(); columnOperation.Comment = property.GetComment(); columnOperation.AddAnnotations(migrationsAnnotations); }
/// <summary> /// Generates a SQL fragment for a computed column definition for the given column metadata. /// </summary> /// <param name="schema"> The schema that contains the table, or <see langword="null" /> to use the default schema. </param> /// <param name="table"> The table that contains the column. </param> /// <param name="name"> The column name. </param> /// <param name="operation"> The column metadata. </param> /// <param name="model"> The target model which may be <see langword="null" /> if the operations exist without a model. </param> /// <param name="builder"> The command builder to use to add the SQL fragment. </param> protected override void ComputedColumnDefinition( string schema, string table, string name, ColumnOperation operation, IModel model, MigrationCommandListBuilder builder) { builder.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(name)); builder .Append(" AS (") .Append(operation.ComputedColumnSql) .Append(")"); if (operation.ComputedColumnIsStored == true) { builder.Append(" STORED"); } if (operation.Collation != null) { builder .Append(" COLLATE ") .Append(operation.Collation); } }
protected override string GetColumnType( [CanBeNull] string schema, [NotNull] string table, [NotNull] string name, [NotNull] ColumnOperation operation, [CanBeNull] IModel model) { var storeType = base.GetColumnType(schema, table, name, operation, model); var identity = operation[JetAnnotationNames.Identity] as string; if (identity != null || operation[JetAnnotationNames.ValueGenerationStrategy] as JetValueGenerationStrategy? == JetValueGenerationStrategy.IdentityColumn) { if (string.Equals(storeType, "counter", StringComparison.OrdinalIgnoreCase) || string.Equals(storeType, "identity", StringComparison.OrdinalIgnoreCase) || string.Equals(storeType, "autoincrement", StringComparison.OrdinalIgnoreCase) || string.Equals(storeType, "integer", StringComparison.OrdinalIgnoreCase)) { storeType = "counter"; if (!string.IsNullOrEmpty(identity) && identity != "1, 1") { storeType += $"({identity})"; } } } return(storeType); }
private string GetColumnTypeWithCharSetAndCollation(ColumnOperation operation, string columnType, IProperty property) { var charSet = property != null ? property[MySQLAnnotationNames.Charset] : operation[MySQLAnnotationNames.Charset]; if (charSet != null) { const string characterSetClausePattern = @"CHARACTER SET \w+"; var characterSetClause = $@"CHARACTER SET {charSet}"; columnType = Regex.IsMatch(columnType, characterSetClausePattern, RegexOptions.IgnoreCase) ? Regex.Replace(columnType, characterSetClausePattern, characterSetClause) : columnType.TrimEnd() + " " + characterSetClause; } var collation = property != null ? property[MySQLAnnotationNames.Collation] : operation[MySQLAnnotationNames.Collation]; if (collation != null) { const string collationClausePattern = @"COLLATE \w+"; var collationClause = $@"COLLATE {collation}"; columnType = Regex.IsMatch(columnType, collationClausePattern, RegexOptions.IgnoreCase) ? Regex.Replace(columnType, collationClausePattern, collationClause) : columnType.TrimEnd() + " " + collationClause; } return(columnType); }
/// <summary> /// Initializes a new instance of the <see cref="MigrationColumnOperationEventData" /> class. /// </summary> /// <param name="eventDefinition">The event definition.</param> /// <param name="messageGenerator">A delegate that generates a log message for this event.</param> /// <param name="columnOperation">The column operation.</param> public MigrationColumnOperationEventData( EventDefinitionBase eventDefinition, Func <EventDefinitionBase, EventData, string> messageGenerator, ColumnOperation columnOperation) : base(eventDefinition, messageGenerator) { ColumnOperation = columnOperation; }
/// <summary> /// Generates a SQL fragment for a computed column definition for the given column metadata. /// </summary> /// <param name="schema"> The schema that contains the table, or <c>null</c> to use the default schema. </param> /// <param name="table"> The table that contains the column. </param> /// <param name="name"> The column name. </param> /// <param name="operation"> The column metadata. </param> /// <param name="model"> The target model which may be <c>null</c> if the operations exist without a model. </param> /// <param name="builder"> The command builder to use to add the SQL fragment. </param> protected override void ComputedColumnDefinition( string schema, string table, string name, ColumnOperation operation, IModel model, MigrationCommandListBuilder builder) => throw new NotSupportedException(SqliteStrings.ComputedColumnsNotSupported);
private void AlterColumnNotSupport(ColumnOperation op) { //https://blog.csdn.net/jaycee110905/article/details/39586817 //https://www.runoob.com/sqlite/sqlite-truncate-table.html //https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&ch=3&tn=98010089_dg&wd=sqlite%20%E5%88%A0%E9%99%A4%E5%88%97&oq=sqlite%2520alter%2520table&rsv_pq=e3e1382a001eec8b&rsv_t=647bzZl%2FgReQOf4SytHN7djqaiBYMaloAKnqBUXpTLSJzCpwLXenj%2BqkuF%2BnoYk0h%2B0&rqlang=cn&rsv_enter=1&rsv_dl=tb&rsv_btype=t&inputT=2081&rsv_sug3=19&rsv_sug1=20&rsv_sug7=100&bs=sqlite%20alter%20table this.AddRun(new GenerationExceptionRun { Message = $"SQLite 不支持列的修改和删除语句,请手动操作列:{op.TableName}.{op.ColumnName}。" }); }
private static IEnumerable <string> GetColumnNamespaces(ColumnOperation columnOperation) { yield return(columnOperation.ClrType.Namespace); var alterColumnOperation = columnOperation as AlterColumnOperation; if (alterColumnOperation?.OldColumn != null) { yield return(alterColumnOperation.OldColumn.ClrType.Namespace); } }
private void Initialize( ColumnOperation columnOperation, IProperty property, Type clrType, bool isNullable, IEnumerable <IAnnotation> migrationsAnnotations, bool inline = false, IEntityType userDefinedType = null) { var columnType = userDefinedType != null?userDefinedType.GetTableName() : property.GetConfiguredColumnType(); if (property.ClrType.IsList() && !CassandraTypeMappingSource.CLR_TYPE_MAPPINGS.ContainsKey(property.ClrType)) { Type genericType; if (clrType.IsGenericType) { genericType = clrType.GenericTypeArguments.First(); } else { genericType = clrType.GetElementType(); } if (!CassandraTypeMappingSource.CLR_TYPE_MAPPINGS.ContainsKey(genericType)) { var targetEntityType = property.DeclaringEntityType.GetRootType(); var et = targetEntityType.Model.FindEntityType(genericType); columnType = columnType.Replace(genericType.Name, et.GetTableName()); } } columnOperation.ClrType = clrType; columnOperation.ColumnType = columnType; columnOperation.MaxLength = property.GetMaxLength(); columnOperation.IsUnicode = property.IsUnicode(); columnOperation.IsFixedLength = property.IsFixedLength(); columnOperation.IsRowVersion = property.ClrType == typeof(byte[]) && property.IsConcurrencyToken && property.ValueGenerated == ValueGenerated.OnAddOrUpdate; columnOperation.IsNullable = isNullable; var defaultValue = userDefinedType != null ? null : GetDefaultValue(property); columnOperation.DefaultValue = (defaultValue == DBNull.Value ? null : defaultValue) ?? (inline || isNullable ? null : userDefinedType != null ? null : GetDefaultValue(columnOperation.ClrType)); columnOperation.DefaultValueSql = property.GetDefaultValueSql(); columnOperation.ComputedColumnSql = property.GetComputedColumnSql(); columnOperation.Comment = property.GetComment(); columnOperation.AddAnnotations(migrationsAnnotations); }
/// <summary> /// 增加不允许为空的约束 /// </summary> /// <param name="op">列操作对象的实体对象</param> protected override void AddNotNullConstraint(ColumnOperation op) { using (var sql = this.Writer()) { sql.Write("ALTER TABLE "); sql.Write(this.Quote(op.TableName)); sql.Write(" MODIFY "); sql.Indent++; this.GenerateColumnDeclaration(sql, op.ColumnName, op.DataType, op.Length, true, op.IsForeignKey); sql.Write(";"); this.AddRun(sql); } }
protected override void RemoveNotNullConstraint(ColumnOperation op) { using (var sql = this.Writer()) { sql.Write("ALTER TABLE "); sql.Write(this.Quote(op.TableName)); sql.WriteLine(); sql.Indent++; sql.Write("ALTER COLUMN "); this.GenerateColumnDeclaration(sql, op.ColumnName, op.DbType, op.Length, false, op.IsForeignKey); this.AddRun(sql); } }
private static IEnumerable<string> GetColumnNamespaces(ColumnOperation columnOperation) { foreach (var ns in columnOperation.ClrType.GetNamespaces()) { yield return ns; } var alterColumnOperation = columnOperation as AlterColumnOperation; if (alterColumnOperation?.OldColumn != null) { foreach (var ns in alterColumnOperation.OldColumn.ClrType.GetNamespaces()) { yield return ns; } } }
private static string GetColumnTypeWithCharSet(ColumnOperation operation, string columnType) { var charSet = operation[MySqlAnnotationNames.CharSet]; if (charSet != null) { const string characterSetClausePattern = @"CHARACTER SET \w+"; var characterSetClause = $@"CHARACTER SET {charSet}"; columnType = Regex.IsMatch(columnType, characterSetClausePattern, RegexOptions.IgnoreCase) ? Regex.Replace(columnType, characterSetClausePattern, characterSetClause) : columnType.TrimEnd() + " " + characterSetClause; } return(columnType); }
protected override void RemoveNotNullConstraint(ColumnOperation op) { using (var sql = this.Writer()) { sql.Write("ALTER TABLE "); sql.Write(this.Quote(op.TableName)); sql.WriteLine(); sql.Indent++; sql.Write("MODIFY "); sql.Write(this.Quote(op.ColumnName)); sql.Write(" NULL"); this.AddRun(sql); } }
protected override void ColumnDefinition(string schema, string table, string name, ColumnOperation operation, IModel model, MigrationCommandListBuilder builder) { var columnType = operation.ColumnType ?? GetColumnType(schema, table, name, operation, model); builder .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(name)) .Append(" ") .Append(operation.IsNullable && !operation.ClrType.IsArray ? $" Nullable({columnType})" : columnType); }
/// <summary> /// 生成删除非空的列约束的语句 /// </summary> /// <param name="op">列操作的实例对象</param> protected override void RemoveNotNullConstraint(ColumnOperation op) { //SQLite 不支持 }
private bool ColumnAnnotationRemoved(string annotrationName, ColumnOperation oldColumn, ColumnOperation newColumn) => oldColumn.FindAnnotation(annotrationName) != null && newColumn.FindAnnotation(annotrationName) == null;
protected override string GetColumnType(string schema, string table, string name, ColumnOperation operation, IModel model) => GetColumnTypeWithCharSetAndCollation( operation, base.GetColumnType(schema, table, name, operation, model), (model.GetRelationalModel().FindTable(table, schema)?.FindColumn(name) != null) ? FindProperty(model, schema, table, name) : null);
private void ColumnDefinitionWithCharSet(string schema, string table, string name, ColumnOperation operation, IModel model, MigrationCommandListBuilder builder) { if (operation.ComputedColumnSql != null) { ComputedColumnDefinition(schema, table, name, operation, model, builder); return; } var property = (model.GetRelationalModel().FindTable(table, schema)?.FindColumn(name) != null) ? FindProperty(model, schema, table, name) : null; var columnType = operation.ColumnType != null ? GetColumnTypeWithCharSetAndCollation(operation, operation.ColumnType, property) : GetColumnType(schema, table, name, operation, model); builder .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(name)) .Append(" ") .Append(columnType); builder.Append(operation.IsNullable ? " NULL" : " NOT NULL"); DefaultValue(operation.DefaultValue, operation.DefaultValueSql, columnType, builder); }
/// <summary> /// Generates a SQL fragment for a column definition for the given column metadata. /// </summary> /// <param name="schema"> The schema that contains the table, or <c>null</c> to use the default schema. </param> /// <param name="table"> The table that contains the column. </param> /// <param name="name"> The column name. </param> /// <param name="operation"> The column metadata. </param> /// <param name="model"> The target model which may be <c>null</c> if the operations exist without a model. </param> /// <param name="builder"> The command builder to use to add the SQL fragment. </param> protected override void ColumnDefinition( string schema, string table, string name, ColumnOperation operation, IModel model, MigrationCommandListBuilder builder) { Check.NotEmpty(name, nameof(name)); Check.NotNull(operation, nameof(operation)); Check.NotNull(builder, nameof(builder)); var matchType = operation.ColumnType ?? GetColumnType(schema, table, name, operation, model); var matchLen = ""; var match = _typeRegex.Match(matchType ?? "-"); if (match.Success) { matchType = match.Groups[1].Value.ToLower(); if (!string.IsNullOrWhiteSpace(match.Groups[2].Value)) { matchLen = match.Groups[2].Value; } } var valueGenerationStrategy = MySQLValueGenerationStrategyCompatibility.GetValueGenerationStrategy(operation.GetAnnotations().OfType <IAnnotation>().ToArray()); var autoIncrement = false; if (valueGenerationStrategy == MySQLValueGenerationStrategy.IdentityColumn && string.IsNullOrWhiteSpace(operation.DefaultValueSql) && operation.DefaultValue == null) { switch (matchType) { case "tinyint": case "smallint": case "mediumint": case "int": case "bigint": autoIncrement = true; break; case "datetime": case "timestamp": operation.DefaultValueSql = $"CURRENT_TIMESTAMP({matchLen})"; break; } } string onUpdateSql = null; if (operation.IsRowVersion || valueGenerationStrategy == MySQLValueGenerationStrategy.ComputedColumn) { switch (matchType) { case "datetime": case "timestamp": if (string.IsNullOrWhiteSpace(operation.DefaultValueSql) && operation.DefaultValue == null) { operation.DefaultValueSql = $"CURRENT_TIMESTAMP({matchLen})"; } onUpdateSql = $"CURRENT_TIMESTAMP({matchLen})"; break; } } if (operation.ComputedColumnSql == null) { ColumnDefinitionWithCharSet(schema, table, name, operation, model, builder); if (autoIncrement) { builder.Append(" AUTO_INCREMENT"); } else { if (onUpdateSql != null) { builder .Append(" ON UPDATE ") .Append(onUpdateSql); } } } else { builder .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(name)) .Append(" ") .Append(operation.ColumnType ?? GetColumnType(schema, table, name, operation, model)); builder .Append(" AS ") .Append($"({operation.ComputedColumnSql})"); if (operation.IsNullable) { builder.Append(" NULL"); } } }
protected override void ColumnDefinition(string schema, string table, string name, ColumnOperation operation, IModel model, MigrationCommandListBuilder builder) { builder.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(name)) .Append(" ") .Append(operation.ColumnType ?? GetColumnType(schema, table, name, operation, model)); var valueGenerationStrategy = operation[FbAnnotationNames.ValueGenerationStrategy] as FbValueGenerationStrategy?; if (valueGenerationStrategy == FbValueGenerationStrategy.IdentityColumn) { builder.Append(" GENERATED BY DEFAULT AS IDENTITY"); } DefaultValue(operation.DefaultValue, operation.DefaultValueSql, operation.ColumnType, builder); if (!operation.IsNullable) { builder.Append(" NOT NULL"); } }
/// <summary> /// Generates a SQL fragment for a column definition for the given column metadata. /// </summary> /// <param name="schema"> The schema that contains the table, or <c>null</c> to use the default schema. </param> /// <param name="table"> The table that contains the column. </param> /// <param name="name"> The column name. </param> /// <param name="operation"> The column metadata. </param> /// <param name="model"> The target model which may be <c>null</c> if the operations exist without a model. </param> /// <param name="builder"> The command builder to use to add the SQL fragment. </param> protected override void ColumnDefinition( [CanBeNull] string schema, [NotNull] string table, [NotNull] string name, [NotNull] ColumnOperation operation, [CanBeNull] IModel model, [NotNull] MigrationCommandListBuilder builder) { Check.NotEmpty(name, nameof(name)); Check.NotNull(operation, nameof(operation)); Check.NotNull(builder, nameof(builder)); var matchType = operation.ColumnType ?? GetColumnType(schema, table, name, operation, model); var matchLen = ""; var match = _typeRe.Match(matchType ?? "-"); if (match.Success) { matchType = match.Groups[1].Value.ToLower(); if (!string.IsNullOrWhiteSpace(match.Groups[2].Value)) { matchLen = match.Groups[2].Value; } } var valueGenerationStrategy = MySqlValueGenerationStrategyCompatibility.GetValueGenerationStrategy(operation.GetAnnotations().OfType <IAnnotation>().ToArray()); var autoIncrement = false; if (valueGenerationStrategy == MySqlValueGenerationStrategy.IdentityColumn && string.IsNullOrWhiteSpace(operation.DefaultValueSql) && operation.DefaultValue == null) { switch (matchType) { case "tinyint": case "smallint": case "mediumint": case "int": case "bigint": autoIncrement = true; break; case "datetime": if (!_connectionInfo.ServerVersion.SupportsDateTime6) { throw new InvalidOperationException( $"Error in {table}.{name}: DATETIME does not support values generated " + "on Add or Update in MySql <= 5.5, try explicitly setting the column type to TIMESTAMP"); } goto case "timestamp"; case "timestamp": operation.DefaultValueSql = $"CURRENT_TIMESTAMP({matchLen})"; break; } } string onUpdateSql = null; if (operation.IsRowVersion || valueGenerationStrategy == MySqlValueGenerationStrategy.ComputedColumn) { switch (matchType) { case "datetime": if (!_connectionInfo.ServerVersion.SupportsDateTime6) { throw new InvalidOperationException( $"Error in {table}.{name}: DATETIME does not support values generated " + "on Add or Update in MySql <= 5.5, try explicitly setting the column type to TIMESTAMP"); } goto case "timestamp"; case "timestamp": if (string.IsNullOrWhiteSpace(operation.DefaultValueSql) && operation.DefaultValue == null) { operation.DefaultValueSql = $"CURRENT_TIMESTAMP({matchLen})"; } onUpdateSql = $"CURRENT_TIMESTAMP({matchLen})"; break; } } if (operation.ComputedColumnSql == null) { base.ColumnDefinition( schema, table, name, operation, model, builder); if (autoIncrement) { builder.Append(" AUTO_INCREMENT"); } else { if (onUpdateSql != null) { builder .Append(" ON UPDATE ") .Append(onUpdateSql); } } } else { builder .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(name)) .Append(" ") .Append(operation.ColumnType ?? GetColumnType(schema, table, name, operation, model)); builder .Append(" AS ") .Append($"({operation.ComputedColumnSql})"); if (operation.IsNullable && _connectionInfo.ServerVersion.SupportsNullableGeneratedColumns) { builder.Append(" NULL"); } } }
private bool ColumnAnnotationRemoved(string annotrationName, ColumnOperation oldColumn, ColumnOperation newColumn) => !ColumnAnnotationAdded(annotrationName, oldColumn, newColumn);
private static bool IsIdentity(ColumnOperation operation) => operation[JetAnnotationNames.Identity] != null || operation[JetAnnotationNames.ValueGenerationStrategy] as JetValueGenerationStrategy? == JetValueGenerationStrategy.IdentityColumn;
protected abstract void RemoveNotNullConstraint(ColumnOperation op);
// protected override string GetColumnType(string schema, string table, string name, ColumnOperation operation, IModel model) // { // return base.GetColumnType(schema, table, name, operation, model); // } protected override void ColumnDefinition(string schema, string table, string name, ColumnOperation operation, IModel model, MigrationCommandListBuilder builder) { var ut = model.FindEntityType(operation.ClrType); var isUserDefinedType = ut != null && ut.IsUserDefinedType(); var columnType = operation.ColumnType ?? GetColumnType(schema, table, name, operation, model); var entityType = model.GetEntityTypes().First(s => s.GetTableName() == table); builder .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(name)) .Append(" ") .Append(columnType); if (entityType.GetStaticColumns().Contains(name)) { builder.Append(" STATIC"); } }
protected override void ColumnDefinition(string schema, string table, string name, ColumnOperation operation, IModel model, MigrationCommandListBuilder builder) { if (operation.ComputedColumnSql == null) { var annotation = operation.FindAnnotation(ModelBuilderExtensions.CaseInsensitiveAnnotationKey); if (annotation?.Value is bool caseInsensitive) { if (operation.ColumnType == null) { operation.ColumnType = GetColumnType(schema, table, name, operation, model); } operation.ColumnType += " COLLATE " + (caseInsensitive ? _caseInsensitiveCollation : _caseSensitiveCollation); } } base.ColumnDefinition(schema, table, name, operation, model, builder); }