protected override void ApplyProviderSpecificMappings(ModelBuilder modelBuilder) { modelBuilder.HasDefaultSchema("dbo"); foreach (var entity in modelBuilder.Model.GetEntityTypes()) { var tableId = StoreObjectIdentifier.Table(entity.GetTableName().ToLower(), entity.GetSchema()); entity.SetTableName(tableId.Name); foreach (var property in entity.GetProperties()) { property.SetColumnName(property.GetColumnName(tableId).ToLower()); } foreach (var key in entity.GetKeys()) { key.SetName(key.GetName().ToLower()); } foreach (var key in entity.GetForeignKeys()) { key.SetConstraintName(key.GetConstraintName().ToLower()); } foreach (var index in entity.GetIndexes()) { index.SetDatabaseName(index.GetDatabaseName().ToLower()); } } }
public static void ApplyHypertables(this DbContext context) { if (context.Database.IsNpgsql()) { context.Database.ExecuteSqlRaw("CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;"); var entityTypes = context.Model.GetEntityTypes(); foreach (var entityType in entityTypes) { foreach (var property in entityType.GetProperties()) { if (property.PropertyInfo.GetCustomAttribute(typeof(HypertableColumnAttribute)) != null) { var tableName = entityType.GetTableName(); var schema = entityType.GetSchema(); var identifier = StoreObjectIdentifier.Table(tableName, schema); var columnName = property.GetColumnName(identifier); if (property.ClrType == typeof(DateTime)) { context.Database.ExecuteSqlRaw($"SELECT create_hypertable('\"{tableName}\"', '{columnName}');"); } else { context.Database.ExecuteSqlRaw($"SELECT create_hypertable('\"{tableName}\"', '{columnName}', chunk_time_interval => 604800000000);"); context.Database.ExecuteSqlRaw($@"CREATE FUNCTION current_microfortnight() RETURNS BIGINT LANGUAGE SQL STABLE AS $$ SELECT CAST(1209600 * EXTRACT(EPOCH FROM CURRENT_TIME) / 1000000 AS BIGINT) $$; SELECT set_integer_now_func('""{columnName}""', 'current_microfortnight');"); } } } } } }
public override IEnumerable <IAnnotation> For(IColumn column) { var table = StoreObjectIdentifier.Table(column.Table.Name, column.Table.Schema); var identityProperty = column.PropertyMappings.Where( m => m.TableMapping.IsSharedTablePrincipal && m.TableMapping.EntityType == m.Property.DeclaringEntityType) .Select(m => m.Property) .FirstOrDefault( p => p.GetValueGenerationStrategy(table) == SqlServerValueGenerationStrategy.IdentityColumn); if (identityProperty != null) { var seed = identityProperty.GetIdentitySeed(table); var increment = identityProperty.GetIdentityIncrement(table); yield return(new Annotation( SqlServerAnnotationNames.Identity, string.Format(CultureInfo.InvariantCulture, "{0}, {1}", seed ?? 1, increment ?? 1))); } // Model validation ensures that these facets are the same on all mapped properties var property = column.PropertyMappings.First().Property; if (property.IsSparse() is bool isSparse) { yield return(new Annotation(SqlServerAnnotationNames.Sparse, isSparse)); } }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public override ResultSetMapping AppendInsertOperation( StringBuilder commandStringBuilder, IReadOnlyModificationCommand command, int commandPosition, out bool requiresTransaction) { // If no database-generated columns need to be read back, just do a simple INSERT (default behavior). // If there are generated columns but there are no triggers defined on the table, we can do a simple INSERT ... OUTPUT // (without INTO), which is also the default behavior, doesn't require a transaction and is the most efficient. if (command.ColumnModifications.All(o => !o.IsRead) || !HasAnyTriggers(command)) { return(base.AppendInsertOperation(commandStringBuilder, command, commandPosition, out requiresTransaction)); } // SQL Server doesn't allow INSERT ... OUTPUT on tables with triggers. // If the only generated column is an IDENTITY, do INSERT+SELECT which is relatively fast. // Otherwise fall back to INSERT ... OUTPUT INTO @inserted; SELECT ... FROM @inserted. var table = StoreObjectIdentifier.Table(command.TableName, command.Schema); return(command.ColumnModifications.All( o => !o.IsKey || !o.IsRead || o.Property?.GetValueGenerationStrategy(table) == SqlServerValueGenerationStrategy.IdentityColumn) ? AppendInsertAndSelectOperations(commandStringBuilder, command, commandPosition, out requiresTransaction) : AppendInsertSingleRowWithOutputInto( commandStringBuilder, command, command.ColumnModifications.Where(o => o.IsKey).ToList(), command.ColumnModifications.Where(o => o.IsRead).ToList(), commandPosition, out requiresTransaction)); }
/// <inheritdoc /> public virtual void ProcessModelFinalizing(IConventionModelBuilder modelBuilder, IConventionContext <IConventionModelBuilder> context) { var maxLength = modelBuilder.Metadata.GetMaxIdentifierLength(); var tables = new Dictionary <(string TableName, string Schema), List <IConventionEntityType> >(); TryUniquifyTableNames(modelBuilder.Metadata, tables, maxLength); var columns = new Dictionary <string, IConventionProperty>(StringComparer.Ordinal); var keys = new Dictionary <string, IConventionKey>(StringComparer.Ordinal); var foreignKeys = new Dictionary <string, IConventionForeignKey>(StringComparer.Ordinal); var indexes = new Dictionary <string, IConventionIndex>(StringComparer.Ordinal); foreach (var table in tables) { columns.Clear(); keys.Clear(); foreignKeys.Clear(); var storeObject = StoreObjectIdentifier.Table(table.Key.TableName, table.Key.Schema); foreach (var entityType in table.Value) { TryUniquifyColumnNames(entityType, columns, storeObject, maxLength); TryUniquifyKeyNames(entityType, keys, storeObject, maxLength); TryUniquifyForeignKeyNames(entityType, foreignKeys, storeObject, maxLength); TryUniquifyIndexNames(entityType, indexes, storeObject, maxLength); } } }
private static List <string>?GetNullableColumns(IReadOnlyIndex index) { var tableName = index.DeclaringEntityType.GetTableName(); if (tableName == null) { return(null); } var nullableColumns = new List <string>(); var table = StoreObjectIdentifier.Table(tableName, index.DeclaringEntityType.GetSchema()); foreach (var property in index.Properties) { var columnName = property.GetColumnName(table); if (columnName == null) { return(null); } if (!property.IsColumnNullable(table)) { continue; } nullableColumns.Add(columnName); } return(nullableColumns); }
/// <summary> /// <para> /// Finds the first <see cref="IForeignKey" /> that is mapped to the same constraint in a shared table. /// </para> /// <para> /// This method is typically used by database providers (and other extensions). It is generally /// not used in application code. /// </para> /// </summary> /// <param name="foreignKey"> The foreign key. </param> /// <param name="tableName"> The table name. </param> /// <param name="schema"> The schema. </param> /// <returns> The foreign key if found, or <see langword="null" /> if none was found.</returns> public static IForeignKey FindSharedTableRootForeignKey( [NotNull] this IForeignKey foreignKey, [NotNull] string tableName, [CanBeNull] string schema) { Check.NotNull(foreignKey, nameof(foreignKey)); Check.NotNull(tableName, nameof(tableName)); var foreignKeyName = foreignKey.GetConstraintName(tableName, schema, foreignKey.PrincipalEntityType.GetTableName(), foreignKey.PrincipalEntityType.GetSchema()); var rootForeignKey = foreignKey; var storeObject = StoreObjectIdentifier.Table(tableName, schema); // Limit traversal to avoid getting stuck in a cycle (validation will throw for these later) // Using a hashset is detrimental to the perf when there are no cycles for (var i = 0; i < Metadata.Internal.RelationalEntityTypeExtensions.MaxEntityTypesSharingTable; i++) { var linkedKey = rootForeignKey.DeclaringEntityType .FindRowInternalForeignKeys(storeObject) .SelectMany(fk => fk.PrincipalEntityType.GetForeignKeys()) .FirstOrDefault(k => k.GetConstraintName(tableName, schema, k.PrincipalEntityType.GetTableName(), k.PrincipalEntityType.GetSchema()) == foreignKeyName); if (linkedKey == null) { break; } rootForeignKey = linkedKey; } return(rootForeignKey == foreignKey ? null : rootForeignKey); }
//// Adjusted implementation of //// https://github.com/dotnet/efcore/blob/v5.0.0-rc.2.20475.6/src/EFCore.SqlServer/Metadata/Internal/SqlServerAnnotationProvider.cs#L185 ///// <summary> ///// This is an internal API that supports the Entity Framework Core infrastructure and not subject to ///// the same compatibility standards as public APIs. It may be changed or removed without notice in ///// any release. You should only use it directly in your code with extreme caution and knowing that ///// doing so can result in application failures when updating to a new Entity Framework Core release. ///// </summary> public override IEnumerable<IAnnotation> For(IColumn column) { //Debugger.Launch(); var table = StoreObjectIdentifier.Table(column.Table.Name, column.Table.Schema); var property = column.PropertyMappings.Where( m => m.TableMapping.IsSharedTablePrincipal && m.TableMapping.EntityType == m.Property.DeclaringEntityType) .Select(m => m.Property) .FirstOrDefault( p => p.IsPrimaryKey() && p.DeclaringEntityType.FindPrimaryKey().Properties.Count() == 1 && // primary key should have one property p.AsProperty().GetValueGeneratedConfigurationSource() == null && // check whether the ValueGenerated is not set explicitly via configuration p.ClrType == typeof(Identifier)); if (property != null) { var modelStrategy = property.DeclaringEntityType.Model.GetValueGenerationStrategy(); var prop = property.AsProperty(); prop.SetValueGenerated(ValueGenerated.OnAdd, ConfigurationSource.Explicit); if (modelStrategy == SqlServerValueGenerationStrategy.IdentityColumn && SqlServerPropertyExtensions.IsCompatibleWithValueGeneration<TDatabaseClrType>(property)) { prop.SetValueGenerationStrategy<TDatabaseClrType>(modelStrategy); // throws error, because Identifier is not allowed type like int } } return base.For(column); }
public static void ApplyDatabaseServerSpecificConventions(this ModelBuilder modelBuilder, string databaseEngine) { if ("SqlServer".Equals(databaseEngine, StringComparison.InvariantCultureIgnoreCase)) { return; } foreach (var entity in modelBuilder.Model.GetEntityTypes()) { entity.SetTableName(entity.GetTableName().ToLowerInvariant()); foreach (var property in entity.GetProperties()) { var tableId = StoreObjectIdentifier.Table(entity.GetTableName()); var columnName = property.GetColumnName(tableId) ?? property.GetDefaultColumnName(tableId); property.SetColumnName(columnName.ToLowerInvariant()); } foreach (var key in entity.GetKeys()) { key.SetName(key.GetName().ToLowerInvariant()); } foreach (var key in entity.GetForeignKeys()) { key.SetConstraintName(key.GetConstraintName().ToLowerInvariant()); } foreach (var index in entity.GetIndexes()) { index.SetDatabaseName(index.GetDatabaseName().ToLowerInvariant()); } } }
/// <inheritdoc /> public virtual void ProcessModelFinalizing( IConventionModelBuilder modelBuilder, IConventionContext <IConventionModelBuilder> context) { foreach (var entityType in modelBuilder.Metadata.GetEntityTypes()) { foreach (var property in entityType.GetDeclaredProperties()) { var strategy = SqlServerValueGenerationStrategy.None; // Needed for the annotation to show up in the model snapshot var table = entityType.GetTableName(); if (table != null) { strategy = property.GetValueGenerationStrategy(StoreObjectIdentifier.Table(table, entityType.GetSchema())); } else { var view = entityType.GetViewName(); if (view != null) { strategy = property.GetValueGenerationStrategy(StoreObjectIdentifier.View(view, entityType.GetViewSchema())); } } if (strategy != SqlServerValueGenerationStrategy.None) { property.Builder.HasValueGenerationStrategy(strategy); } } } }
public void Customize(Microsoft.EntityFrameworkCore.ModelBuilder modelBuilder, DbContext context) { _modelCustomizer.Customize(modelBuilder, context); foreach (IMutableEntityType entityType in modelBuilder.Model.GetEntityTypes()) { entityType.SetQueryFilter(GetFilter(entityType.ClrType)); if (entityType.GetSchema() != null) { entityType.SetSchema(entityType.GetSchema().ToLowerInvariant()); } entityType.SetTableName(entityType.GetTableName().ToLowerInvariant()); foreach (IMutableProperty property in entityType.GetProperties()) { var storeObjectIdentifier = StoreObjectIdentifier.Table(entityType.GetTableName(), entityType.GetSchema()); property.SetColumnName(property.GetColumnName(storeObjectIdentifier).ToLowerInvariant()); } } Expression <Func <Parameter, bool> > parameterFilter = t => t.SpecificSchema != "pg_catalog" && t.SpecificSchema != "information_schema"; modelBuilder.Model.FindEntityType(typeof(Parameter)).SetQueryFilter(parameterFilter); Expression <Func <Routine, bool> > routineFilter = t => t.SpecificSchema != "pg_catalog" && t.SpecificSchema != "information_schema" && t.DataType != "internal"; modelBuilder.Model.FindEntityType(typeof(Routine)).SetQueryFilter(routineFilter); }
private void ProcessTableChanged( IConventionEntityTypeBuilder entityTypeBuilder, string?oldTable, string?oldSchema, string?newTable, string?newSchema) { var primaryKey = entityTypeBuilder.Metadata.FindPrimaryKey(); if (primaryKey == null) { return; } var oldLink = oldTable != null ? entityTypeBuilder.Metadata.FindRowInternalForeignKeys(StoreObjectIdentifier.Table(oldTable, oldSchema)) : null; var newLink = newTable != null ? entityTypeBuilder.Metadata.FindRowInternalForeignKeys(StoreObjectIdentifier.Table(newTable, newSchema)) : null; if ((oldLink?.Any() != true && newLink?.Any() != true) || newLink == null) { return; } foreach (var property in primaryKey.Properties) { property.Builder.ValueGenerated(GetValueGenerated(property, StoreObjectIdentifier.Table(newTable !, newSchema))); } }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public static bool AreCompatible( [NotNull] this IKey key, [NotNull] IKey duplicateKey, [NotNull] string tableName, [CanBeNull] string schema, bool shouldThrow) { var storeObject = StoreObjectIdentifier.Table(tableName, schema); if (!key.Properties.Select(p => p.GetColumnName(storeObject)) .SequenceEqual(duplicateKey.Properties.Select(p => p.GetColumnName(storeObject)))) { if (shouldThrow) { throw new InvalidOperationException( RelationalStrings.DuplicateKeyColumnMismatch( key.Properties.Format(), key.DeclaringEntityType.DisplayName(), duplicateKey.Properties.Format(), duplicateKey.DeclaringEntityType.DisplayName(), key.DeclaringEntityType.GetSchemaQualifiedTableName(), key.GetName(tableName, schema), key.Properties.FormatColumns(storeObject), duplicateKey.Properties.FormatColumns(storeObject))); } return(false); } return(true); }
public static void ApplySnakeCaseNamingConvention(this ModelBuilder builder) { foreach (var entity in builder.Model.GetEntityTypes()) { entity.SetTableName(entity.GetTableName().ToSnakeCase()); foreach (var property in entity.GetProperties()) { var tableIdentifier = StoreObjectIdentifier.Table(entity.GetTableName(), null); property.SetColumnName(property.GetColumnName(tableIdentifier).ToSnakeCase()); } foreach (var key in entity.GetKeys()) { key.SetName(key.GetName().ToSnakeCase()); } foreach (var foreignKey in entity.GetForeignKeys()) { foreignKey.SetConstraintName(foreignKey.GetConstraintName().ToSnakeCase()); } foreach (var index in entity.GetIndexes()) { index.SetDatabaseName(index.GetDatabaseName().ToSnakeCase()); } } }
public override IEnumerable <IAnnotation> For(ITableIndex index) { // Model validation ensures that these facets are the same on all mapped indexes var modelIndex = index.MappedIndexes.First(); var table = index.Table; if (modelIndex.IsClustered(StoreObjectIdentifier.Table(table.Name, table.Schema)) is bool isClustered) { yield return(new Annotation(SqlServerAnnotationNames.Clustered, isClustered)); } if (modelIndex.GetIncludeProperties() is IReadOnlyList <string> includeProperties) { var includeColumns = includeProperties .Select( p => modelIndex.DeclaringEntityType.FindProperty(p) ! .GetColumnName(StoreObjectIdentifier.Table(table.Name, table.Schema))) .ToArray(); yield return(new Annotation( SqlServerAnnotationNames.Include, includeColumns)); } if (modelIndex.IsCreatedOnline() is bool isOnline) { yield return(new Annotation(SqlServerAnnotationNames.CreatedOnline, isOnline)); } if (modelIndex.GetFillFactor() is int fillFactor) { yield return(new Annotation(SqlServerAnnotationNames.FillFactor, fillFactor)); } }
protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); foreach (var entity in builder.Model.GetEntityTypes()) { entity.SetTableName(entity.GetTableName().ToSnakeCase()); foreach (var property in entity.GetProperties()) { property.SetColumnName(property.GetColumnName( StoreObjectIdentifier.Table(entity.GetTableName(), property.DeclaringEntityType.GetSchema()) ).ToSnakeCase()); } foreach (var key in entity.GetKeys()) { key.SetName(key.GetName().ToSnakeCase()); } foreach (var key in entity.GetForeignKeys()) { key.SetConstraintName(key.GetConstraintName().ToSnakeCase()); } foreach (var index in entity.GetIndexes()) { index.SetDatabaseName(index.GetDatabaseName().ToSnakeCase()); } } }
private string CreateIndexFilter(IIndex index) { var tableName = index.DeclaringEntityType.GetTableName(); if (tableName == null) { return(null); } var table = StoreObjectIdentifier.Table(tableName, index.DeclaringEntityType.GetSchema()); var nullableColumns = index.Properties .Where(property => property.IsColumnNullable(table)) .Select(property => property.GetColumnName(table)) .ToList(); var builder = new StringBuilder(); for (var i = 0; i < nullableColumns.Count; i++) { if (i != 0) { builder.Append(" AND "); } builder .Append(_sqlGenerationHelper.DelimitIdentifier(nullableColumns[i])) .Append(" IS NOT NULL"); } return(builder.ToString()); }
/// <summary> /// <para> /// Finds the first <see cref="IIndex" /> that is mapped to the same index in a shared table. /// </para> /// <para> /// This method is typically used by database providers (and other extensions). It is generally /// not used in application code. /// </para> /// </summary> /// <param name="index"> The index. </param> /// <param name="tableName"> The table name. </param> /// <param name="schema"> The schema. </param> /// <returns> The index found, or <see langword="null" /> if none was found.</returns> public static IIndex FindSharedTableRootIndex( [NotNull] this IIndex index, [NotNull] string tableName, [CanBeNull] string schema) { Check.NotNull(index, nameof(index)); Check.NotNull(tableName, nameof(tableName)); var table = StoreObjectIdentifier.Table(tableName, schema); var indexName = index.GetDatabaseName(tableName, schema); var rootIndex = index; // Limit traversal to avoid getting stuck in a cycle (validation will throw for these later) // Using a hashset is detrimental to the perf when there are no cycles for (var i = 0; i < Metadata.Internal.RelationalEntityTypeExtensions.MaxEntityTypesSharingTable; i++) { var linkedIndex = rootIndex.DeclaringEntityType .FindRowInternalForeignKeys(table) .SelectMany(fk => fk.PrincipalEntityType.GetIndexes()) .FirstOrDefault(i => i.GetDatabaseName(tableName, schema) == indexName); if (linkedIndex == null) { break; } rootIndex = linkedIndex; } return(rootIndex == index ? null : rootIndex); }
/// <summary> /// Returns the store value generation strategy to set for the given property. /// </summary> /// <param name="property">The property.</param> /// <returns>The store value generation strategy to set for the given property.</returns> protected override ValueGenerated?GetValueGenerated(IConventionProperty property) { var tableName = property.DeclaringEntityType.GetTableName(); return(tableName == null ? null : GetValueGenerated(property, StoreObjectIdentifier.Table(tableName, property.DeclaringEntityType.GetSchema()))); }
private static string FormatInclude(IIndex index, string tableName, string schema) => index.GetIncludeProperties() == null ? "{}" : "{'" + string.Join("', '", index.GetIncludeProperties().Select(p => index.DeclaringEntityType.FindProperty(p) ?.GetColumnName(StoreObjectIdentifier.Table(tableName, schema)))) + "'}";
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public override IEnumerable <IAnnotation> For(IColumn column, bool designTime) { if (!designTime) { yield break; } var table = StoreObjectIdentifier.Table(column.Table.Name, column.Table.Schema); var identityProperty = column.PropertyMappings.Where( m => m.TableMapping.IsSharedTablePrincipal && m.TableMapping.EntityType == m.Property.DeclaringEntityType) .Select(m => m.Property) .FirstOrDefault( p => p.GetValueGenerationStrategy(table) == SqlServerValueGenerationStrategy.IdentityColumn); if (identityProperty != null) { var seed = identityProperty.GetIdentitySeed(table); var increment = identityProperty.GetIdentityIncrement(table); yield return(new Annotation( SqlServerAnnotationNames.Identity, string.Format(CultureInfo.InvariantCulture, "{0}, {1}", seed ?? 1, increment ?? 1))); } // Model validation ensures that these facets are the same on all mapped properties var property = column.PropertyMappings.First().Property; if (property.IsSparse() is bool isSparse) { yield return(new Annotation(SqlServerAnnotationNames.Sparse, isSparse)); } var entityType = column.Table.EntityTypeMappings.First().EntityType; if (entityType.IsTemporal() && designTime) { var periodStartPropertyName = entityType.GetTemporalPeriodStartPropertyName(); var periodEndPropertyName = entityType.GetTemporalPeriodEndPropertyName(); var periodStartProperty = entityType.GetProperty(periodStartPropertyName !); var periodEndProperty = entityType.GetProperty(periodEndPropertyName !); var storeObjectIdentifier = StoreObjectIdentifier.Table(table.Name, table.Schema); var periodStartColumnName = periodStartProperty.GetColumnName(storeObjectIdentifier); var periodEndColumnName = periodEndProperty.GetColumnName(storeObjectIdentifier); if (column.Name == periodStartColumnName || column.Name == periodEndColumnName) { yield return(new Annotation(SqlServerAnnotationNames.IsTemporal, true)); yield return(new Annotation(SqlServerAnnotationNames.TemporalPeriodStartColumnName, periodStartColumnName)); yield return(new Annotation(SqlServerAnnotationNames.TemporalPeriodEndColumnName, periodEndColumnName)); } } }
public override IEnumerable <IAnnotation> For(IColumn column, bool designTime) { if (!designTime) { yield break; } var table = StoreObjectIdentifier.Table(column.Table.Name, column.Table.Schema); var properties = column.PropertyMappings.Select(m => m.Property).ToArray(); if (column.PropertyMappings.Where( m => m.TableMapping.IsSharedTablePrincipal && m.TableMapping.EntityType == m.Property.DeclaringEntityType) .Select(m => m.Property) .FirstOrDefault(p => p.GetValueGenerationStrategy(table) == MySqlValueGenerationStrategy.IdentityColumn) is IProperty identityProperty) { var valueGenerationStrategy = identityProperty.GetValueGenerationStrategy(table); yield return(new Annotation( MySqlAnnotationNames.ValueGenerationStrategy, valueGenerationStrategy)); } else if (properties.FirstOrDefault( p => p.GetValueGenerationStrategy(table) == MySqlValueGenerationStrategy.ComputedColumn) is IProperty computedProperty) { var valueGenerationStrategy = computedProperty.GetValueGenerationStrategy(table); yield return(new Annotation( MySqlAnnotationNames.ValueGenerationStrategy, valueGenerationStrategy)); } // Use an explicitly defined character set, if set. // Otherwise, explicitly use the entity/table or model/database character set, if delegation is enabled. if (GetActualPropertyCharSet(properties, DelegationModes.ApplyToColumns) is string charSet) { yield return(new Annotation( MySqlAnnotationNames.CharSet, charSet)); } // Use an explicitly defined collation, if set. // Otherwise, explicitly use the entity/table or model/database collation, if delegation is enabled. if (GetActualPropertyCollation(properties, DelegationModes.ApplyToColumns) is string collation) { yield return(new Annotation( RelationalAnnotationNames.Collation, collation)); } if (column.PropertyMappings.Select(m => m.Property.GetSpatialReferenceSystem()) .FirstOrDefault(c => c != null) is int srid) { yield return(new Annotation( MySqlAnnotationNames.SpatialReferenceSystemId, srid)); } }
private string GetColumnNameTakingIntoAccountSchema(IProperty property, DatabaseTable table, bool isView = false) { var modelSchema = table.Schema == _defaultSchema ? null : table.Schema; var columnName = isView ? property.GetColumnName(StoreObjectIdentifier.View(table.Name, modelSchema)) : property.GetColumnName(StoreObjectIdentifier.Table(table.Name, modelSchema)); return(columnName); }
public override IEnumerable <IAnnotation> For(IUniqueConstraint constraint) { // Model validation ensures that these facets are the same on all mapped keys var key = constraint.MappedKeys.First(); var table = constraint.Table; if (key.IsClustered(StoreObjectIdentifier.Table(table.Name, table.Schema)) is bool isClustered) { yield return(new Annotation(SqlServerAnnotationNames.Clustered, isClustered)); } }
/// <inheritdoc /> public virtual void ProcessModelFinalizing(IConventionModelBuilder modelBuilder, IConventionContext <IConventionModelBuilder> context) { var nonTphRoots = new HashSet <IConventionEntityType>(); foreach (var entityType in modelBuilder.Metadata.GetEntityTypes()) { if (entityType.BaseType == null) { continue; } var tableName = entityType.GetTableName(); var schema = entityType.GetSchema(); if (tableName != null && (tableName != entityType.BaseType.GetTableName() || schema != entityType.BaseType.GetSchema())) { nonTphRoots.Add(entityType.GetRootType()); foreach (var property in entityType.BaseType.GetProperties()) { if (property.IsPrimaryKey()) { continue; } property.Builder.HasColumnName(null, StoreObjectIdentifier.Table(tableName, schema)); } } var viewName = entityType.GetViewName(); var viewSchema = entityType.GetViewSchema(); if (viewName != null && (viewName != entityType.BaseType.GetViewName() || viewSchema != entityType.BaseType.GetViewSchema())) { nonTphRoots.Add(entityType.GetRootType()); foreach (var property in entityType.BaseType.GetProperties()) { if (property.IsPrimaryKey()) { continue; } property.Builder.HasColumnName(null, StoreObjectIdentifier.View(viewName, viewSchema)); } } } foreach (var root in nonTphRoots) { root.Builder.HasNoDiscriminator(); } }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public override IEnumerable <IAnnotation> For(ITable table, bool designTime) { if (!designTime) { yield break; } var entityType = table.EntityTypeMappings.First().EntityType; // Model validation ensures that these facets are the same on all mapped entity types if (entityType.IsMemoryOptimized()) { yield return(new Annotation(SqlServerAnnotationNames.MemoryOptimized, true)); } if (entityType.IsTemporal() && designTime) { yield return(new Annotation(SqlServerAnnotationNames.IsTemporal, true)); yield return(new Annotation(SqlServerAnnotationNames.TemporalHistoryTableName, entityType.GetHistoryTableName())); yield return(new Annotation(SqlServerAnnotationNames.TemporalHistoryTableSchema, entityType.GetHistoryTableSchema())); // for the RevEng path, we avoid adding period properties to the entity // because we don't want code for them to be generated - they need to be in shadow state // so if we don't find property on the entity, we know it's this scenario // and in that case period column name is actually the same as the period property name annotation // since in RevEng scenario there can't be custom column mapping // see #26007 var storeObjectIdentifier = StoreObjectIdentifier.Table(table.Name, table.Schema); var periodStartPropertyName = entityType.GetPeriodStartPropertyName(); if (periodStartPropertyName != null) { var periodStartProperty = entityType.FindProperty(periodStartPropertyName); var periodStartColumnName = periodStartProperty != null ? periodStartProperty.GetColumnName(storeObjectIdentifier) : periodStartPropertyName; yield return(new Annotation(SqlServerAnnotationNames.TemporalPeriodStartColumnName, periodStartColumnName)); } var periodEndPropertyName = entityType.GetPeriodEndPropertyName(); if (periodEndPropertyName != null) { var periodEndProperty = entityType.FindProperty(periodEndPropertyName); var periodEndColumnName = periodEndProperty != null ? periodEndProperty.GetColumnName(storeObjectIdentifier) : periodEndPropertyName; yield return(new Annotation(SqlServerAnnotationNames.TemporalPeriodEndColumnName, periodEndColumnName)); } } }
// Postgres перевод PascalCase в snake_case protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); // builder.Entity<Entity>() // .Property(e => e.Field) // .HasColumnType("SMALLINT"); // Composite primary key builder.Entity <MarkApproval>().HasIndex( e => new { e.MarkId, e.EmployeeId }).IsUnique(); // Unique constrains builder.Entity <User>() .HasIndex(e => e.Login) .IsUnique(); // builder.Entity<Entity>() // .HasIndex(e => e.BaseSeries) // .IsUnique(); // builder.Entity<Entity>().HasIndex(e => new { e.SubnodeId, e.Code }).IsUnique(); // Default datetime // builder.Entity<Mark>().Property(e => e.EditedDate).HasDefaultValueSql("now()"); foreach (var entity in builder.Model.GetEntityTypes()) { entity.SetTableName(entity.GetTableName().ToSnakeCase()); foreach (var property in entity.GetProperties()) { property.SetColumnName(property.GetColumnName( StoreObjectIdentifier.Table(entity.GetTableName(), property.DeclaringEntityType.GetSchema()) ).ToSnakeCase()); } foreach (var key in entity.GetKeys()) { key.SetName(key.GetName().ToSnakeCase()); } foreach (var key in entity.GetForeignKeys()) { key.SetConstraintName(key.GetConstraintName().ToSnakeCase()); } foreach (var index in entity.GetIndexes()) { index.SetDatabaseName(index.GetDatabaseName().ToSnakeCase()); } } }
/// <summary> /// Returns the store value generation strategy to set for the given property. /// </summary> /// <param name="property">The property.</param> /// <returns>The store value generation strategy to set for the given property.</returns> protected override ValueGenerated?GetValueGenerated(IConventionProperty property) { var tableName = property.DeclaringEntityType.GetTableName(); if (tableName == null) { return(null); } return(GetValueGenerated( property, StoreObjectIdentifier.Table(tableName, property.DeclaringEntityType.GetSchema()), Dependencies.TypeMappingSource)); }
public override IEnumerable <IAnnotation> For(ITableIndex index) { // Model validation ensures that these facets are the same on all mapped indexes var modelIndex = index.MappedIndexes.First(); if (modelIndex.GetCollation() is IReadOnlyList <string> collation) { yield return(new Annotation(RelationalAnnotationNames.Collation, collation)); } if (modelIndex.GetMethod() is string method) { yield return(new Annotation(NpgsqlAnnotationNames.IndexMethod, method)); } if (modelIndex.GetOperators() is IReadOnlyList <string> operators) { yield return(new Annotation(NpgsqlAnnotationNames.IndexOperators, operators)); } if (modelIndex.GetSortOrder() is IReadOnlyList <SortOrder> sortOrder) { yield return(new Annotation(NpgsqlAnnotationNames.IndexSortOrder, sortOrder)); } if (modelIndex.GetNullSortOrder() is IReadOnlyList <SortOrder> nullSortOrder) { yield return(new Annotation(NpgsqlAnnotationNames.IndexNullSortOrder, nullSortOrder)); } if (modelIndex.GetTsVectorConfig() is string configName) { yield return(new Annotation(NpgsqlAnnotationNames.TsVectorConfig, configName)); } if (modelIndex.GetIncludeProperties() is IReadOnlyList <string> includeProperties) { var tableIdentifier = StoreObjectIdentifier.Table(index.Table.Name, index.Table.Schema); yield return(new Annotation( NpgsqlAnnotationNames.IndexInclude, includeProperties .Select(p => modelIndex.DeclaringEntityType.FindProperty(p).GetColumnName(tableIdentifier)) .ToArray())); } var isCreatedConcurrently = modelIndex.IsCreatedConcurrently(); if (isCreatedConcurrently.HasValue) { yield return(new Annotation( NpgsqlAnnotationNames.CreatedConcurrently, isCreatedConcurrently.Value)); } }
/// <inheritdoc /> public virtual void ProcessModelFinalizing( IConventionModelBuilder modelBuilder, IConventionContext <IConventionModelBuilder> context) { var maxLength = modelBuilder.Metadata.GetMaxIdentifierLength(); var tables = new Dictionary <(string TableName, string?Schema), List <IConventionEntityType> >(); TryUniquifyTableNames(modelBuilder.Metadata, tables, maxLength); var columns = new Dictionary <string, IConventionProperty>(); var keys = new Dictionary <string, IConventionKey>(); var foreignKeys = new Dictionary <string, IConventionForeignKey>(); var indexes = new Dictionary <string, IConventionIndex>(); var checkConstraints = new Dictionary <(string, string?), IConventionCheckConstraint>(); var triggers = new Dictionary <string, IConventionTrigger>(); foreach (var((tableName, schema), conventionEntityTypes) in tables) { columns.Clear(); keys.Clear(); foreignKeys.Clear(); if (!IndexesUniqueAcrossTables) { indexes.Clear(); } if (!CheckConstraintsUniqueAcrossTables) { checkConstraints.Clear(); } if (!TriggersUniqueAcrossTables) { triggers.Clear(); } var storeObject = StoreObjectIdentifier.Table(tableName, schema); foreach (var entityType in conventionEntityTypes) { TryUniquifyColumnNames(entityType, columns, storeObject, maxLength); TryUniquifyKeyNames(entityType, keys, storeObject, maxLength); TryUniquifyForeignKeyNames(entityType, foreignKeys, storeObject, maxLength); TryUniquifyIndexNames(entityType, indexes, storeObject, maxLength); TryUniquifyCheckConstraintNames(entityType, checkConstraints, storeObject, maxLength); TryUniquifyTriggerNames(entityType, triggers, storeObject, maxLength); } } }