Example #1
0
        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');");
                     }
                 }
             }
         }
     }
 }
Example #3
0
        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));
    }
Example #5
0
        /// <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);
                }
            }
        }
Example #6
0
    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);
        }
Example #8
0
        //// 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);
        }
Example #9
0
        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());
                }
            }
        }
Example #10
0
        /// <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)));
            }
        }
Example #13
0
        /// <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);
        }
Example #14
0
        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());
                }
            }
        }
Example #15
0
        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));
            }
        }
Example #16
0
        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());
        }
Example #18
0
        /// <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));
                }
            }
        }
Example #22
0
        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);
        }
Example #24
0
        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));
                }
            }
        }
Example #27
0
        // 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());
                }
            }
        }
Example #28
0
        /// <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));
        }
Example #29
0
        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));
            }
        }
Example #30
0
    /// <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);
            }
        }
    }