/// <summary>
        ///     Removes the previous migration.
        /// </summary>
        /// <param name="projectDir">The project's root directory.</param>
        /// <param name="rootNamespace">The project's root namespace.</param>
        /// <param name="force">Don't check to see if the migration has been applied to the database.</param>
        /// <param name="language">The project's language.</param>
        /// <returns>The removed migration files.</returns>
        // TODO: DRY (file names)
        public virtual MigrationFiles RemoveMigration(
            string projectDir,
            string?rootNamespace,
            bool force,
            string?language)
        {
            var files = new MigrationFiles();

            var modelSnapshot = Dependencies.MigrationsAssembly.ModelSnapshot;

            if (modelSnapshot == null)
            {
                throw new OperationException(DesignStrings.NoSnapshot);
            }

            var codeGenerator = Dependencies.MigrationsCodeGeneratorSelector.Select(language);

            IModel?model      = null;
            var    migrations = Dependencies.MigrationsAssembly.Migrations
                                .Select(m => Dependencies.MigrationsAssembly.CreateMigration(m.Value, _activeProvider))
                                .ToList();

            if (migrations.Count != 0)
            {
                var migration = migrations[migrations.Count - 1];
                model = Dependencies.SnapshotModelProcessor.Process(migration.TargetModel);

                if (!Dependencies.MigrationsModelDiffer.HasDifferences(
                        model.GetRelationalModel(), Dependencies.SnapshotModelProcessor.Process(modelSnapshot.Model).GetRelationalModel()))
                {
                    var applied = false;
                    try
                    {
                        applied = Dependencies.HistoryRepository.GetAppliedMigrations().Any(
                            e => e.MigrationId.Equals(migration.GetId(), StringComparison.OrdinalIgnoreCase));
                    }
                    catch (Exception ex) when(force)
                    {
                        Dependencies.OperationReporter.WriteVerbose(ex.ToString());
                        Dependencies.OperationReporter.WriteWarning(
                            DesignStrings.ForceRemoveMigration(migration.GetId(), ex.Message));
                    }

                    if (applied)
                    {
                        if (force)
                        {
                            Dependencies.Migrator.Migrate(
                                migrations.Count > 1
                                    ? migrations[migrations.Count - 2].GetId()
                                    : Migration.InitialDatabase);
                        }
                        else
                        {
                            throw new OperationException(DesignStrings.RevertMigration(migration.GetId()));
                        }
                    }

                    var migrationFileName = migration.GetId() + codeGenerator.FileExtension;
                    var migrationFile     = TryGetProjectFile(projectDir, migrationFileName);
                    if (migrationFile != null)
                    {
                        Dependencies.OperationReporter.WriteInformation(DesignStrings.RemovingMigration(migration.GetId()));
                        File.Delete(migrationFile);
                        files.MigrationFile = migrationFile;
                    }
                    else
                    {
                        Dependencies.OperationReporter.WriteWarning(
                            DesignStrings.NoMigrationFile(migrationFileName, migration.GetType().ShortDisplayName()));
                    }

                    var migrationMetadataFileName = migration.GetId() + ".Designer" + codeGenerator.FileExtension;
                    var migrationMetadataFile     = TryGetProjectFile(projectDir, migrationMetadataFileName);
                    if (migrationMetadataFile != null)
                    {
                        File.Delete(migrationMetadataFile);
                        files.MetadataFile = migrationMetadataFile;
                    }
                    else
                    {
                        Dependencies.OperationReporter.WriteVerbose(
                            DesignStrings.NoMigrationMetadataFile(migrationMetadataFile));
                    }

                    model = migrations.Count > 1
                        ? Dependencies.SnapshotModelProcessor.Process(migrations[migrations.Count - 2].TargetModel)
                        : null;
                }
                else
                {
                    Dependencies.OperationReporter.WriteVerbose(DesignStrings.ManuallyDeleted);
                }
            }

            var modelSnapshotName     = modelSnapshot.GetType().Name;
            var modelSnapshotFileName = modelSnapshotName + codeGenerator.FileExtension;
            var modelSnapshotFile     = TryGetProjectFile(projectDir, modelSnapshotFileName);

            if (model == null)
            {
                if (modelSnapshotFile != null)
                {
                    Dependencies.OperationReporter.WriteInformation(DesignStrings.RemovingSnapshot);
                    File.Delete(modelSnapshotFile);
                    files.SnapshotFile = modelSnapshotFile;
                }
                else
                {
                    Dependencies.OperationReporter.WriteWarning(
                        DesignStrings.NoSnapshotFile(
                            modelSnapshotFileName,
                            modelSnapshot.GetType().ShortDisplayName()));
                }
            }
            else
            {
                var modelSnapshotNamespace = modelSnapshot.GetType().Namespace;
                Check.DebugAssert(!string.IsNullOrEmpty(modelSnapshotNamespace), "modelSnapshotNamespace is null or empty");
                var modelSnapshotCode = codeGenerator.GenerateSnapshot(
                    modelSnapshotNamespace,
                    _contextType,
                    modelSnapshotName,
                    model);

                if (modelSnapshotFile == null)
                {
                    modelSnapshotFile = Path.Combine(
                        GetDirectory(projectDir, null, GetSubNamespace(rootNamespace, modelSnapshotNamespace)),
                        modelSnapshotFileName);
                }

                Dependencies.OperationReporter.WriteInformation(DesignStrings.RevertingSnapshot);
                File.WriteAllText(modelSnapshotFile, modelSnapshotCode, Encoding.UTF8);
            }

            return(files);
        }
        public virtual ScaffoldedMigration ScaffoldMigration(
            [NotNull] string migrationName,
            [NotNull] string rootNamespace,
            [CanBeNull] string subNamespace = null)
        {
            Check.NotEmpty(migrationName, nameof(migrationName));
            Check.NotEmpty(rootNamespace, nameof(rootNamespace));

            if (_migrationsAssembly.FindMigrationId(migrationName) != null)
            {
                throw new OperationException(DesignStrings.DuplicateMigrationName(migrationName));
            }

            var subNamespaceDefaulted = false;

            if (string.IsNullOrEmpty(subNamespace))
            {
                subNamespaceDefaulted = true;
                subNamespace          = "Migrations";
            }

            var lastMigration = _migrationsAssembly.Migrations.LastOrDefault();

            var migrationNamespace = rootNamespace + "." + subNamespace;

            if (subNamespaceDefaulted)
            {
                migrationNamespace = GetNamespace(lastMigration.Value?.AsType(), migrationNamespace);
            }

            var sanitizedContextName = _contextType.Name;
            var genericMarkIndex     = sanitizedContextName.IndexOf('`');

            if (genericMarkIndex != -1)
            {
                sanitizedContextName = sanitizedContextName.Substring(0, genericMarkIndex);
            }

            if (ContainsForeignMigrations(migrationNamespace))
            {
                if (subNamespaceDefaulted)
                {
                    var builder = new StringBuilder()
                                  .Append(rootNamespace)
                                  .Append(".Migrations.");

                    if (sanitizedContextName.EndsWith("Context", StringComparison.Ordinal))
                    {
                        builder.Append(sanitizedContextName.Substring(0, sanitizedContextName.Length - 7));
                    }
                    else
                    {
                        builder
                        .Append(sanitizedContextName)
                        .Append("Migrations");
                    }

                    migrationNamespace = builder.ToString();
                }
                else
                {
                    _logger.LogWarning(
                        DesignEventId.ForeignMigrations,
                        () => DesignStrings.ForeignMigrations(migrationNamespace));
                }
            }

            var modelSnapshot  = _migrationsAssembly.ModelSnapshot;
            var lastModel      = modelSnapshot?.Model;
            var upOperations   = _modelDiffer.GetDifferences(lastModel, _model);
            var downOperations = upOperations.Any()
                ? _modelDiffer.GetDifferences(_model, lastModel)
                : new List <MigrationOperation>();
            var migrationId            = _idGenerator.GenerateId(migrationName);
            var modelSnapshotNamespace = GetNamespace(modelSnapshot?.GetType(), migrationNamespace);

            var modelSnapshotName = sanitizedContextName + "ModelSnapshot";

            if (modelSnapshot != null)
            {
                var lastModelSnapshotName = modelSnapshot.GetType().Name;
                if (lastModelSnapshotName != modelSnapshotName)
                {
                    _logger.LogDebug(
                        DesignEventId.ReusingSnapshotName,
                        () => DesignStrings.ReusingSnapshotName(lastModelSnapshotName));

                    modelSnapshotName = lastModelSnapshotName;
                }
            }

            if (upOperations.Any(o => o.IsDestructiveChange))
            {
                _logger.LogWarning(
                    DesignEventId.DestructiveOperation,
                    () => DesignStrings.DestructiveOperation);
            }

            var migrationCode = _migrationCodeGenerator.GenerateMigration(
                migrationNamespace,
                migrationName,
                upOperations,
                downOperations);
            var migrationMetadataCode = _migrationCodeGenerator.GenerateMetadata(
                migrationNamespace,
                _contextType,
                migrationName,
                migrationId,
                _model);
            var modelSnapshotCode = _migrationCodeGenerator.GenerateSnapshot(
                modelSnapshotNamespace,
                _contextType,
                modelSnapshotName,
                _model);

            return(new ScaffoldedMigration(
                       _migrationCodeGenerator.FileExtension,
                       lastMigration.Key,
                       migrationCode,
                       migrationId,
                       migrationMetadataCode,
                       GetSubNamespace(rootNamespace, migrationNamespace),
                       modelSnapshotCode,
                       modelSnapshotName,
                       GetSubNamespace(rootNamespace, modelSnapshotNamespace)));
        }
Example #3
0
        private IDictionary <Type, Func <DbContext> > FindContextTypes()
        {
            _reporter.WriteVerbose(DesignStrings.FindingContexts);

            var contexts = new Dictionary <Type, Func <DbContext> >();

            // Look for IDesignTimeDbContextFactory implementations
            _reporter.WriteVerbose(DesignStrings.FindingContextFactories);
            var contextFactories = _startupAssembly.GetConstructibleTypes()
                                   .Where(t => typeof(IDesignTimeDbContextFactory <DbContext>).IsAssignableFrom(t));

            foreach (var factory in contextFactories)
            {
                _reporter.WriteVerbose(DesignStrings.FoundContextFactory(factory.ShortDisplayName()));
                var manufacturedContexts =
                    from i in factory.ImplementedInterfaces
                    where i.IsGenericType &&
                    i.GetGenericTypeDefinition() == typeof(IDesignTimeDbContextFactory <>)
                    select i.GenericTypeArguments[0];
                foreach (var context in manufacturedContexts)
                {
                    _reporter.WriteVerbose(DesignStrings.FoundDbContext(context.ShortDisplayName()));
                    contexts.Add(
                        context,
                        () => CreateContextFromFactory(factory.AsType()));
                }
            }

            // Look for DbContext classes registered in the service provider
            var appServices        = _appServicesFactory.Create(_args);
            var registeredContexts = appServices.GetServices <DbContextOptions>()
                                     .Select(o => o.ContextType);

            foreach (var context in registeredContexts.Where(c => !contexts.ContainsKey(c)))
            {
                _reporter.WriteVerbose(DesignStrings.FoundDbContext(context.ShortDisplayName()));
                contexts.Add(
                    context,
                    FindContextFactory(context)
                    ?? (() => (DbContext)ActivatorUtilities.GetServiceOrCreateInstance(appServices, context)));
            }

            // Look for DbContext classes in assemblies
            _reporter.WriteVerbose(DesignStrings.FindingReferencedContexts);
            var types = _startupAssembly.GetConstructibleTypes()
                        .Concat(_assembly.GetConstructibleTypes())
                        .ToList();
            var contextTypes = types.Where(t => typeof(DbContext).IsAssignableFrom(t)).Select(
                t => t.AsType())
                               .Concat(
                types.Where(t => typeof(Migration).IsAssignableFrom(t))
                .Select(t => t.GetCustomAttribute <DbContextAttribute>()?.ContextType)
                .Where(t => t != null))
                               .Distinct();

            foreach (var context in contextTypes.Where(c => !contexts.ContainsKey(c)))
            {
                _reporter.WriteVerbose(DesignStrings.FoundDbContext(context.ShortDisplayName()));
                contexts.Add(
                    context,
                    FindContextFactory(context) ?? (() =>
                {
                    try
                    {
                        return((DbContext)Activator.CreateInstance(context));
                    }
                    catch (MissingMethodException ex)
                    {
                        throw new OperationException(DesignStrings.NoParameterlessConstructor(context.Name), ex);
                    }
                }));
            }

            return(contexts);
        }
        /// <summary>
        ///     Scaffolds a new migration.
        /// </summary>
        /// <param name="migrationName"> The migration's name. </param>
        /// <param name="rootNamespace"> The project's root namespace. </param>
        /// <param name="subNamespace"> The migration's sub-namespace. </param>
        /// <param name="language"> The project's language. </param>
        /// <returns> The scaffolded migration. </returns>
        public virtual ScaffoldedMigration ScaffoldMigration(
            string migrationName,
            string rootNamespace,
            string subNamespace = null,
            string language     = null)
        {
            Check.NotEmpty(migrationName, nameof(migrationName));
            Check.NotEmpty(rootNamespace, nameof(rootNamespace));

            if (Dependencies.MigrationsAssembly.FindMigrationId(migrationName) != null)
            {
                throw new OperationException(DesignStrings.DuplicateMigrationName(migrationName));
            }

            var subNamespaceDefaulted = false;

            if (string.IsNullOrEmpty(subNamespace))
            {
                subNamespaceDefaulted = true;
                subNamespace          = "Migrations";
            }

            var lastMigration = Dependencies.MigrationsAssembly.Migrations.LastOrDefault();

            var migrationNamespace = rootNamespace + "." + subNamespace;

            if (subNamespaceDefaulted)
            {
                migrationNamespace = GetNamespace(lastMigration.Value?.AsType(), migrationNamespace);
            }

            var sanitizedContextName = _contextType.Name;
            var genericMarkIndex     = sanitizedContextName.IndexOf('`');

            if (genericMarkIndex != -1)
            {
                sanitizedContextName = sanitizedContextName.Substring(0, genericMarkIndex);
            }

            if (ContainsForeignMigrations(migrationNamespace))
            {
                if (subNamespaceDefaulted)
                {
                    var builder = new StringBuilder()
                                  .Append(rootNamespace)
                                  .Append(".Migrations.");

                    if (sanitizedContextName.EndsWith("Context", StringComparison.Ordinal))
                    {
                        builder.Append(sanitizedContextName, 0, sanitizedContextName.Length - 7);
                    }
                    else
                    {
                        builder
                        .Append(sanitizedContextName)
                        .Append("Migrations");
                    }

                    migrationNamespace = builder.ToString();
                }
                else
                {
                    Dependencies.OperationReporter.WriteWarning(DesignStrings.ForeignMigrations(migrationNamespace));
                }
            }

            var modelSnapshot  = Dependencies.MigrationsAssembly.ModelSnapshot;
            var lastModel      = Dependencies.SnapshotModelProcessor.Process(modelSnapshot?.Model);
            var upOperations   = Dependencies.MigrationsModelDiffer.GetDifferences(lastModel, Dependencies.Model);
            var downOperations = upOperations.Count > 0
                ? Dependencies.MigrationsModelDiffer.GetDifferences(Dependencies.Model, lastModel)
                : new List <MigrationOperation>();
            var migrationId            = Dependencies.MigrationsIdGenerator.GenerateId(migrationName);
            var modelSnapshotNamespace = GetNamespace(modelSnapshot?.GetType(), migrationNamespace);

            var modelSnapshotName = sanitizedContextName + "ModelSnapshot";

            if (modelSnapshot != null)
            {
                var lastModelSnapshotName = modelSnapshot.GetType().Name;
                if (lastModelSnapshotName != modelSnapshotName)
                {
                    Dependencies.OperationReporter.WriteVerbose(DesignStrings.ReusingSnapshotName(lastModelSnapshotName));

                    modelSnapshotName = lastModelSnapshotName;
                }
            }

            if (upOperations.Any(o => o.IsDestructiveChange))
            {
                Dependencies.OperationReporter.WriteWarning(DesignStrings.DestructiveOperation);
            }

            var codeGenerator = Dependencies.MigrationsCodeGeneratorSelector.Select(language);
            var migrationCode = codeGenerator.GenerateMigration(
                migrationNamespace,
                migrationName,
                upOperations,
                downOperations);
            var migrationMetadataCode = codeGenerator.GenerateMetadata(
                migrationNamespace,
                _contextType,
                migrationName,
                migrationId,
                Dependencies.Model);
            var modelSnapshotCode = codeGenerator.GenerateSnapshot(
                modelSnapshotNamespace,
                _contextType,
                modelSnapshotName,
                Dependencies.Model);

            return(new ScaffoldedMigration(
                       codeGenerator.FileExtension,
                       lastMigration.Key,
                       migrationCode,
                       migrationId,
                       migrationMetadataCode,
                       GetSubNamespace(rootNamespace, migrationNamespace),
                       modelSnapshotCode,
                       modelSnapshotName,
                       GetSubNamespace(rootNamespace, modelSnapshotNamespace)));
        }
        // TODO: DRY (file names)
        public virtual MigrationFiles RemoveMigration([NotNull] string projectDir, [NotNull] string rootNamespace, bool force)
        {
            Check.NotEmpty(projectDir, nameof(projectDir));
            Check.NotEmpty(rootNamespace, nameof(rootNamespace));

            var files = new MigrationFiles();

            var modelSnapshot = _migrationsAssembly.ModelSnapshot;

            if (modelSnapshot == null)
            {
                throw new OperationException(DesignStrings.NoSnapshot);
            }

            var language = _migrationCodeGenerator.FileExtension;

            IModel model      = null;
            var    migrations = _migrationsAssembly.Migrations
                                .Select(m => _migrationsAssembly.CreateMigration(m.Value, _activeProvider))
                                .ToList();

            if (migrations.Count != 0)
            {
                var migration = migrations[migrations.Count - 1];
                model = migration.TargetModel;

                if (!_modelDiffer.HasDifferences(model, modelSnapshot.Model))
                {
                    if (force)
                    {
                        _logger.LogWarning(
                            DesignEventId.ForceRemoveMigration,
                            () => DesignStrings.ForceRemoveMigration(migration.GetId()));
                    }
                    else if (_historyRepository.GetAppliedMigrations().Any(
                                 e => e.MigrationId.Equals(migration.GetId(), StringComparison.OrdinalIgnoreCase)))
                    {
                        throw new OperationException(DesignStrings.UnapplyMigration(migration.GetId()));
                    }

                    var migrationFileName = migration.GetId() + language;
                    var migrationFile     = TryGetProjectFile(projectDir, migrationFileName);
                    if (migrationFile != null)
                    {
                        _logger.LogInformation(
                            DesignEventId.RemovingMigration,
                            () => DesignStrings.RemovingMigration(migration.GetId()));
                        File.Delete(migrationFile);
                        files.MigrationFile = migrationFile;
                    }
                    else
                    {
                        _logger.LogWarning(
                            DesignEventId.NoMigrationFile,
                            () => DesignStrings.NoMigrationFile(migrationFileName, migration.GetType().ShortDisplayName()));
                    }

                    var migrationMetadataFileName = migration.GetId() + ".Designer" + language;
                    var migrationMetadataFile     = TryGetProjectFile(projectDir, migrationMetadataFileName);
                    if (migrationMetadataFile != null)
                    {
                        File.Delete(migrationMetadataFile);
                        files.MetadataFile = migrationMetadataFile;
                    }
                    else
                    {
                        _logger.LogDebug(
                            DesignEventId.NoMigrationMetadataFile,
                            () => DesignStrings.NoMigrationMetadataFile(migrationMetadataFileName));
                    }

                    model = migrations.Count > 1
                        ? migrations[migrations.Count - 2].TargetModel
                        : null;
                }
                else
                {
                    _logger.LogDebug(
                        DesignEventId.ManuallyDeleted,
                        () => DesignStrings.ManuallyDeleted);
                }
            }

            var modelSnapshotName     = modelSnapshot.GetType().Name;
            var modelSnapshotFileName = modelSnapshotName + language;
            var modelSnapshotFile     = TryGetProjectFile(projectDir, modelSnapshotFileName);

            if (model == null)
            {
                if (modelSnapshotFile != null)
                {
                    _logger.LogInformation(
                        DesignEventId.RemovingSnapshot,
                        () => DesignStrings.RemovingSnapshot);
                    File.Delete(modelSnapshotFile);
                    files.SnapshotFile = modelSnapshotFile;
                }
                else
                {
                    _logger.LogWarning(
                        DesignEventId.NoSnapshotFile,
                        () => DesignStrings.NoSnapshotFile(modelSnapshotFileName, modelSnapshot.GetType().ShortDisplayName()));
                }
            }
            else
            {
                var modelSnapshotNamespace = modelSnapshot.GetType().Namespace;
                Debug.Assert(!string.IsNullOrEmpty(modelSnapshotNamespace));
                var modelSnapshotCode = _migrationCodeGenerator.GenerateSnapshot(
                    modelSnapshotNamespace,
                    _contextType,
                    modelSnapshotName,
                    model);

                if (modelSnapshotFile == null)
                {
                    modelSnapshotFile = Path.Combine(
                        GetDirectory(projectDir, null, GetSubNamespace(rootNamespace, modelSnapshotNamespace)),
                        modelSnapshotFileName);
                }

                _logger.LogInformation(
                    DesignEventId.RevertingSnapshot,
                    () => DesignStrings.RevertingSnapshot);
                File.WriteAllText(modelSnapshotFile, modelSnapshotCode, Encoding.UTF8);
            }

            return(files);
        }
        /// <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>
        protected virtual IMutableForeignKey VisitForeignKey([NotNull] ModelBuilder modelBuilder, [NotNull] DatabaseForeignKey foreignKey)
        {
            Check.NotNull(modelBuilder, nameof(modelBuilder));
            Check.NotNull(foreignKey, nameof(foreignKey));

            if (foreignKey.PrincipalTable == null)
            {
                _reporter.WriteWarning(
                    DesignStrings.ForeignKeyScaffoldErrorPrincipalTableNotFound(foreignKey.DisplayName()));
                return(null);
            }

            if (foreignKey.Table == null)
            {
                return(null);
            }

            var dependentEntityType = modelBuilder.Model.FindEntityType(GetEntityTypeName(foreignKey.Table));

            if (dependentEntityType == null)
            {
                return(null);
            }

            var unmappedDependentColumns = foreignKey.Columns
                                           .Where(c => _unmappedColumns.Contains(c))
                                           .Select(c => c.Name)
                                           .ToList();

            if (unmappedDependentColumns.Count > 0)
            {
                _reporter.WriteWarning(
                    DesignStrings.ForeignKeyScaffoldErrorPropertyNotFound(
                        foreignKey.DisplayName(),
                        string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator, unmappedDependentColumns)));
                return(null);
            }

            var dependentProperties = foreignKey.Columns
                                      .Select(GetPropertyName)
                                      .Select(name => dependentEntityType.FindProperty(name))
                                      .ToList()
                                      .AsReadOnly();

            var principalEntityType = modelBuilder.Model.FindEntityType(GetEntityTypeName(foreignKey.PrincipalTable));

            if (principalEntityType == null)
            {
                _reporter.WriteWarning(
                    DesignStrings.ForeignKeyScaffoldErrorPrincipalTableScaffoldingError(
                        foreignKey.DisplayName(),
                        foreignKey.PrincipalTable.DisplayName()));
                return(null);
            }

            var unmappedPrincipalColumns = foreignKey.PrincipalColumns
                                           .Where(pc => principalEntityType.FindProperty(GetPropertyName(pc)) == null)
                                           .Select(pc => pc.Name)
                                           .ToList();

            if (unmappedPrincipalColumns.Count > 0)
            {
                _reporter.WriteWarning(
                    DesignStrings.ForeignKeyScaffoldErrorPropertyNotFound(
                        foreignKey.DisplayName(),
                        string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator, unmappedPrincipalColumns)));
                return(null);
            }

            var principalPropertiesMap = foreignKey.PrincipalColumns
                                         .Select(
                fc => (property: principalEntityType.FindProperty(GetPropertyName(fc)), column: fc)).ToList();
            var principalProperties = principalPropertiesMap
                                      .Select(tuple => tuple.property)
                                      .ToList();

            var principalKey = principalEntityType.FindKey(principalProperties);

            if (principalKey == null)
            {
                var index = principalEntityType.FindIndex(principalProperties.AsReadOnly());
                if (index?.IsUnique == true)
                {
                    // ensure all principal properties are non-nullable even if the columns
                    // are nullable on the database. EF's concept of a key requires this.
                    var nullablePrincipalProperties =
                        principalPropertiesMap.Where(tuple => tuple.property.IsNullable).ToList();
                    if (nullablePrincipalProperties.Count > 0)
                    {
                        _reporter.WriteWarning(
                            DesignStrings.ForeignKeyPrincipalEndContainsNullableColumns(
                                foreignKey.DisplayName(),
                                index.Relational().Name,
                                nullablePrincipalProperties.Select(tuple => tuple.column.DisplayName()).ToList()
                                .Aggregate((a, b) => a + "," + b)));

                        nullablePrincipalProperties
                        .ToList()
                        .ForEach(tuple => tuple.property.IsNullable = false);
                    }

                    principalKey = principalEntityType.AddKey(principalProperties);
                }
                else
                {
                    var principalColumns = foreignKey.PrincipalColumns.Select(c => c.Name).ToList();

                    _reporter.WriteWarning(
                        DesignStrings.ForeignKeyScaffoldErrorPrincipalKeyNotFound(
                            foreignKey.DisplayName(),
                            string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator, principalColumns),
                            principalEntityType.DisplayName()));

                    return(null);
                }
            }

            var key = dependentEntityType.AddForeignKey(
                dependentProperties, principalKey, principalEntityType);

            var dependentKey   = dependentEntityType.FindKey(dependentProperties);
            var dependentIndex = dependentEntityType.FindIndex(dependentProperties);

            key.IsUnique = dependentKey != null ||
                           dependentIndex?.IsUnique == true;

            if (!string.IsNullOrEmpty(foreignKey.Name) &&
                foreignKey.Name != ConstraintNamer.GetDefaultName(key))
            {
                key.Relational().ConstraintName = foreignKey.Name;
            }

            AssignOnDeleteAction(foreignKey, key);

            key.AddAnnotations(foreignKey.GetAnnotations());

            return(key);
        }
        public void Sequences()
        {
            using (var scratch = SqlServerTestStore.Create("SqlServerE2E"))
            {
                scratch.ExecuteNonQuery(@"
CREATE SEQUENCE CountByTwo
    START WITH 1
    INCREMENT BY 2;

CREATE SEQUENCE CyclicalCountByThree
    START WITH 6
    INCREMENT BY 3
    MAXVALUE 27
    MINVALUE 0
    CYCLE;

CREATE SEQUENCE TinyIntSequence
    AS tinyint
    START WITH 1;

CREATE SEQUENCE SmallIntSequence
    AS smallint
    START WITH 1;

CREATE SEQUENCE IntSequence
    AS int
    START WITH 1;

CREATE SEQUENCE DecimalSequence
    AS decimal;

CREATE SEQUENCE NumericSequence
    AS numeric;");


                var expectedFileSet = new FileSet(
                    new FileSystemFileService(),
                    Path.Combine("ReverseEngineering", "Expected"),
                    contents => contents.Replace("{{connectionString}}", scratch.ConnectionString))
                {
                    Files = new List <string> {
                        "SequenceContext.cs"
                    }
                };

                var filePaths = Generator.Generate(
                    scratch.ConnectionString,
                    Enumerable.Empty <string>(),
                    Enumerable.Empty <string>(),
                    TestProjectDir + Path.DirectorySeparatorChar,
                    outputPath: null,     // not used for this test
                    rootNamespace: TestNamespace,
                    contextName: "SequenceContext",
                    useDataAnnotations: false,
                    overwriteFiles: false,
                    useDatabaseNames: false);

                var actualFileSet = new FileSet(InMemoryFiles, Path.GetFullPath(TestProjectDir))
                {
                    Files = new[] { filePaths.ContextFile }.Concat(filePaths.EntityTypeFiles).Select(Path.GetFileName).ToList()
                };

                Assert.Contains("warn: " + DesignStrings.BadSequenceType("DecimalSequence", "decimal"), _reporter.Messages);
                Assert.Contains("warn: " + DesignStrings.BadSequenceType("NumericSequence", "numeric"), _reporter.Messages);
                Assert.Equal(2, _reporter.Messages.Count(m => m.StartsWith("warn: ")));

                AssertEqualFileContents(expectedFileSet, actualFileSet);
                AssertCompile(actualFileSet);
            }
        }
        /// <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>
        protected virtual PropertyBuilder VisitColumn([NotNull] EntityTypeBuilder builder, [NotNull] DatabaseColumn column)
        {
            Check.NotNull(builder, nameof(builder));
            Check.NotNull(column, nameof(column));

            var typeScaffoldingInfo = GetTypeScaffoldingInfo(column);

            if (typeScaffoldingInfo == null)
            {
                _unmappedColumns.Add(column);
                _reporter.WriteWarning(
                    DesignStrings.CannotFindTypeMappingForColumn(column.DisplayName(), column.StoreType));
                return(null);
            }

            var clrType = typeScaffoldingInfo.ClrType;

            if (column.IsNullable)
            {
                clrType = clrType.MakeNullable();
            }

            if (clrType == typeof(bool) &&
                column.DefaultValueSql != null)
            {
                _reporter.WriteWarning(
                    DesignStrings.NonNullableBoooleanColumnHasDefaultConstraint(column.DisplayName()));

                clrType = clrType.MakeNullable();
            }

            var property = builder.Property(clrType, GetPropertyName(column));

            property.HasColumnName(column.Name);

            if (!typeScaffoldingInfo.IsInferred &&
                !string.IsNullOrWhiteSpace(column.StoreType))
            {
                property.HasColumnType(column.StoreType);
            }

            if (typeScaffoldingInfo.ScaffoldUnicode.HasValue)
            {
                property.IsUnicode(typeScaffoldingInfo.ScaffoldUnicode.Value);
            }

            if (typeScaffoldingInfo.ScaffoldFixedLength == true)
            {
                property.IsFixedLength();
            }

            if (typeScaffoldingInfo.ScaffoldMaxLength.HasValue)
            {
                property.HasMaxLength(typeScaffoldingInfo.ScaffoldMaxLength.Value);
            }

            if (column.ValueGenerated == ValueGenerated.OnAdd)
            {
                property.ValueGeneratedOnAdd();
            }

            if (column.ValueGenerated == ValueGenerated.OnUpdate)
            {
                property.ValueGeneratedOnUpdate();
            }

            if (column.ValueGenerated == ValueGenerated.OnAddOrUpdate)
            {
                property.ValueGeneratedOnAddOrUpdate();
            }

            if (column.DefaultValueSql != null)
            {
                property.HasDefaultValueSql(column.DefaultValueSql);
            }

            if (column.ComputedColumnSql != null)
            {
                property.HasComputedColumnSql(column.ComputedColumnSql);
            }

            if (!(column.Table.PrimaryKey?.Columns.Contains(column) ?? false))
            {
                property.IsRequired(!column.IsNullable);
            }

            if ((bool?)column[ScaffoldingAnnotationNames.ConcurrencyToken] == true)
            {
                property.IsConcurrencyToken();
            }

            property.Metadata.Scaffolding().ColumnOrdinal = column.Table.Columns.IndexOf(column);

            property.Metadata.AddAnnotations(
                column.GetAnnotations().Where(
                    a => a.Name != ScaffoldingAnnotationNames.ConcurrencyToken));

            return(property);
        }
        /// <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>
        protected virtual KeyBuilder VisitPrimaryKey([NotNull] EntityTypeBuilder builder, [NotNull] DatabaseTable table)
        {
            Check.NotNull(builder, nameof(builder));
            Check.NotNull(table, nameof(table));

            var primaryKey = table.PrimaryKey;

            if (primaryKey == null)
            {
                _reporter.WriteWarning(DesignStrings.MissingPrimaryKey(table.DisplayName()));
                return(null);
            }

            var unmappedColumns = primaryKey.Columns
                                  .Where(c => _unmappedColumns.Contains(c))
                                  .Select(c => c.Name)
                                  .ToList();

            if (unmappedColumns.Count > 0)
            {
                _reporter.WriteWarning(
                    DesignStrings.PrimaryKeyErrorPropertyNotFound(
                        table.DisplayName(),
                        string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator, unmappedColumns)));
                return(null);
            }

            var keyBuilder = builder.HasKey(primaryKey.Columns.Select(GetPropertyName).ToArray());


            if (primaryKey.Columns.Count == 1 &&
                primaryKey.Columns[0].ValueGenerated == null &&
                primaryKey.Columns[0].DefaultValueSql == null)
            {
                var property = builder.Metadata.FindProperty(GetPropertyName(primaryKey.Columns[0]))?.AsProperty();
                if (property != null)
                {
                    var dummyLogger = new DiagnosticsLogger <DbLoggerCategory.Model>(
                        new ScopedLoggerFactory(new LoggerFactory(), dispose: true),
                        new LoggingOptions(),
                        new DiagnosticListener(""),
                        new LoggingDefinitions());

                    var conventionalValueGenerated = new RelationalValueGeneratorConvention(dummyLogger).GetValueGenerated(property);
                    if (conventionalValueGenerated == ValueGenerated.OnAdd)
                    {
                        property.ValueGenerated = ValueGenerated.Never;
                    }
                }
            }

            if (!string.IsNullOrEmpty(primaryKey.Name) &&
                primaryKey.Name != ConstraintNamer.GetDefaultName(keyBuilder.Metadata))
            {
                keyBuilder.HasName(primaryKey.Name);
            }

            keyBuilder.Metadata.AddAnnotations(primaryKey.GetAnnotations());

            return(keyBuilder);
        }
Example #10
0
        public void GetMigrations_throws_when_target_and_migrations_assemblies_mismatch()
        {
            using (var directory = new TempDirectory())
            {
                var targetDir = directory.Path;
                var source    = new BuildSource
                {
                    TargetDir  = targetDir,
                    References =
                    {
                        BuildReference.ByName("System.Diagnostics.DiagnosticSource",                                             true),
                        BuildReference.ByName("System.Interactive.Async",                                                        true),
                        BuildReference.ByName("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
                        BuildReference.ByName("Microsoft.AspNetCore.Hosting.Abstractions",                                       true),
                        BuildReference.ByName("Microsoft.EntityFrameworkCore",                                                   true),
                        BuildReference.ByName("Microsoft.EntityFrameworkCore.Design",                                            true),
                        BuildReference.ByName("Microsoft.EntityFrameworkCore.Relational",                                        true),
                        BuildReference.ByName("Microsoft.EntityFrameworkCore.Relational.Design",                                 true),
                        BuildReference.ByName("Microsoft.EntityFrameworkCore.SqlServer",                                         true),
                        BuildReference.ByName("Microsoft.Extensions.Caching.Abstractions",                                       true),
                        BuildReference.ByName("Microsoft.Extensions.Caching.Memory",                                             true),
                        BuildReference.ByName("Microsoft.Extensions.Configuration.Abstractions",                                 true),
                        BuildReference.ByName("Microsoft.Extensions.DependencyInjection",                                        true),
                        BuildReference.ByName("Microsoft.Extensions.DependencyInjection.Abstractions",                           true),
                        BuildReference.ByName("Microsoft.Extensions.FileProviders.Abstractions",                                 true),
                        BuildReference.ByName("Microsoft.Extensions.Logging",                                                    true),
                        BuildReference.ByName("Microsoft.Extensions.Logging.Abstractions",                                       true),
                        BuildReference.ByName("Microsoft.Extensions.Options",                                                    true),
                        BuildReference.ByName("Remotion.Linq",                                                                   true)
                    },
                    Sources = { @"
                            using Microsoft.EntityFrameworkCore;
                            using Microsoft.EntityFrameworkCore.Infrastructure;
                            using Microsoft.EntityFrameworkCore.Migrations;

                            namespace MyProject
                            {
                                internal class MyContext : DbContext
                                {
                                    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
                                    {
                                        optionsBuilder
                                            .UseSqlServer(
                                                ""Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=MyProject.MyContext;Integrated Security=True"",
                                                b => b.MigrationsAssembly(""UnknownAssembly""));
                                    }
                                }

                                namespace Migrations
                                {
                                    [DbContext(typeof(MyContext))]
                                    [Migration(""20151215152142_MyMigration"")]
                                    public class MyMigration : Migration
                                    {
                                        protected override void Up(MigrationBuilder migrationBuilder)
                                        {
                                        }
                                    }
                                }
                            }" }
                };
                var build = source.Build();
                using (var executor = CreateExecutorFromBuildResult(build, "MyProject"))
                {
                    var ex = Assert.Throws <WrappedException>(
                        () => executor.GetMigrations("MyContext"));

                    Assert.Equal(
                        DesignStrings.MigrationsAssemblyMismatch(build.TargetName, "UnknownAssembly"),
                        ex.Message);
                }
            }
        }
Example #11
0
        private void GenerateProperty(IProperty property, bool useDataAnnotations)
        {
            var lines = new List <string> {
                $".{nameof(EntityTypeBuilder.Property)}(e => e.{property.Name})"
            };

            var annotations = property.GetAnnotations().ToList();

            RemoveAnnotation(ref annotations, CoreAnnotationNames.MaxLength);
            RemoveAnnotation(ref annotations, CoreAnnotationNames.Precision);
            RemoveAnnotation(ref annotations, CoreAnnotationNames.Scale);
            RemoveAnnotation(ref annotations, CoreAnnotationNames.TypeMapping);
            RemoveAnnotation(ref annotations, CoreAnnotationNames.Unicode);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.ColumnName);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.ViewColumnName);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.ColumnType);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.DefaultValue);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.DefaultValueSql);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.Comment);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.Collation);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.ComputedColumnSql);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.ComputedColumnIsStored);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.IsFixedLength);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.TableColumnMappings);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.ViewColumnMappings);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.RelationalOverrides);
            RemoveAnnotation(ref annotations, ScaffoldingAnnotationNames.ColumnOrdinal);

            if (!useDataAnnotations)
            {
                if (!property.IsNullable &&
                    property.ClrType.IsNullableType() &&
                    !property.IsPrimaryKey())
                {
                    lines.Add($".{nameof(PropertyBuilder.IsRequired)}()");
                }

                var columnName = property.GetColumnName();

                if (columnName != null &&
                    columnName != property.Name)
                {
                    lines.Add(
                        $".{nameof(RelationalPropertyBuilderExtensions.HasColumnName)}" +
                        $"({_code.Literal(columnName)})");
                }

                var viewColumnName = property.GetViewColumnName();

                if (viewColumnName != null &&
                    viewColumnName != columnName)
                {
                    lines.Add(
                        $".{nameof(RelationalPropertyBuilderExtensions.HasViewColumnName)}" +
                        $"({_code.Literal(columnName)})");
                }

                var columnType = property.GetConfiguredColumnType();

                if (columnType != null)
                {
                    lines.Add(
                        $".{nameof(RelationalPropertyBuilderExtensions.HasColumnType)}" +
                        $"({_code.Literal(columnType)})");
                }

                var maxLength = property.GetMaxLength();

                if (maxLength.HasValue)
                {
                    lines.Add(
                        $".{nameof(PropertyBuilder.HasMaxLength)}" +
                        $"({_code.Literal(maxLength.Value)})");
                }
            }

            var precision = property.GetPrecision();
            var scale     = property.GetScale();

            if (precision != null && scale != null && scale != 0)
            {
                lines.Add(
                    $".{nameof(PropertyBuilder.HasPrecision)}" +
                    $"({_code.Literal(precision.Value)}, {_code.Literal(scale.Value)})");
            }
            else if (precision != null)
            {
                lines.Add(
                    $".{nameof(PropertyBuilder.HasPrecision)}" +
                    $"({_code.Literal(precision.Value)})");
            }

            if (property.IsUnicode() != null)
            {
                lines.Add(
                    $".{nameof(PropertyBuilder.IsUnicode)}" +
                    $"({(property.IsUnicode() == false ? "false" : "")})");
            }

            if (property.IsFixedLength() != null)
            {
                lines.Add(
                    $".{nameof(RelationalPropertyBuilderExtensions.IsFixedLength)}()");
            }

            if (property.GetDefaultValue() != null)
            {
                lines.Add(
                    $".{nameof(RelationalPropertyBuilderExtensions.HasDefaultValue)}" +
                    $"({_code.UnknownLiteral(property.GetDefaultValue())})");
            }

            if (property.GetDefaultValueSql() != null)
            {
                lines.Add(
                    $".{nameof(RelationalPropertyBuilderExtensions.HasDefaultValueSql)}" +
                    $"({_code.Literal(property.GetDefaultValueSql())})");
            }

            if (property.GetComputedColumnSql() != null)
            {
                lines.Add(
                    $".{nameof(RelationalPropertyBuilderExtensions.HasComputedColumnSql)}" +
                    $"({_code.Literal(property.GetComputedColumnSql())}" +
                    (property.GetComputedColumnIsStored() is bool computedColumnIsStored
                        ? $", stored: {_code.Literal(computedColumnIsStored)})"
                        : ")"));
            }

            if (property.GetComment() != null)
            {
                lines.Add(
                    $".{nameof(RelationalPropertyBuilderExtensions.HasComment)}" +
                    $"({_code.Literal(property.GetComment())})");
            }

            if (property.GetCollation() != null)
            {
                lines.Add(
                    $".{nameof(RelationalPropertyBuilderExtensions.UseCollation)}" +
                    $"({_code.Literal(property.GetCollation())})");
            }

            var valueGenerated = property.ValueGenerated;
            var isRowVersion   = false;

            if (((IConventionProperty)property).GetValueGeneratedConfigurationSource().HasValue &&
                RelationalValueGenerationConvention.GetValueGenerated(property) != valueGenerated)
            {
                var methodName = valueGenerated switch
                {
                    ValueGenerated.OnAdd => nameof(PropertyBuilder.ValueGeneratedOnAdd),
                    ValueGenerated.OnAddOrUpdate => property.IsConcurrencyToken
                        ? nameof(PropertyBuilder.IsRowVersion)
                        : nameof(PropertyBuilder.ValueGeneratedOnAddOrUpdate),
                    ValueGenerated.OnUpdate => nameof(PropertyBuilder.ValueGeneratedOnUpdate),
                    ValueGenerated.Never => nameof(PropertyBuilder.ValueGeneratedNever),
                    _ => throw new InvalidOperationException(DesignStrings.UnhandledEnumValue($"{nameof(ValueGenerated)}.{valueGenerated}"))
                };

                lines.Add($".{methodName}()");
            }

            if (property.IsConcurrencyToken &&
                !isRowVersion)
            {
                lines.Add($".{nameof(PropertyBuilder.IsConcurrencyToken)}()");
            }

            var annotationsToRemove = new List <IAnnotation>();

            foreach (var annotation in annotations)
            {
                if (annotation.Value == null ||
                    _annotationCodeGenerator.IsHandledByConvention(property, annotation))
                {
                    annotationsToRemove.Add(annotation);
                }
                else
                {
                    var methodCall = _annotationCodeGenerator.GenerateFluentApi(property, annotation);
                    if (methodCall != null)
                    {
                        lines.Add(_code.Fragment(methodCall));
                        annotationsToRemove.Add(annotation);
                    }
                }
            }

            lines.AddRange(GenerateAnnotations(annotations.Except(annotationsToRemove)));

            switch (lines.Count)
            {
            case 1:
                return;

            case 2:
                lines = new List <string> {
                    lines[0] + lines[1]
                };
                break;
            }

            AppendMultiLineFluentApi(property.DeclaringEntityType, lines);
        }
        private void GenerateProperty(IProperty property)
        {
            var lines = new List <string> {
                $".{nameof(EntityTypeBuilder.Property)}({_code.Lambda(new[] { property.Name }, " e ")})"
            };

            var annotations = _annotationCodeGenerator
                              .FilterIgnoredAnnotations(property.GetAnnotations())
                              .ToDictionary(a => a.Name, a => a);

            _annotationCodeGenerator.RemoveAnnotationsHandledByConventions(property, annotations);
            annotations.Remove(ScaffoldingAnnotationNames.ColumnOrdinal);

            if (_useDataAnnotations)
            {
                // Strip out any annotations handled as attributes - these are already handled when generating
                // the entity's properties
                // Only relational ones need to be removed here. Core ones are already removed by FilterIgnoredAnnotations
                annotations.Remove(RelationalAnnotationNames.ColumnName);
                annotations.Remove(RelationalAnnotationNames.ColumnType);

                _ = _annotationCodeGenerator.GenerateDataAnnotationAttributes(property, annotations);
            }
            else
            {
                if ((!_useNullableReferenceTypes || property.ClrType.IsValueType) &&
                    !property.IsNullable &&
                    property.ClrType.IsNullableType() &&
                    !property.IsPrimaryKey())
                {
                    lines.Add($".{nameof(PropertyBuilder.IsRequired)}()");
                }

                var columnType = property.GetConfiguredColumnType();
                if (columnType != null)
                {
                    lines.Add(
                        $".{nameof(RelationalPropertyBuilderExtensions.HasColumnType)}({_code.Literal(columnType)})");
                    annotations.Remove(RelationalAnnotationNames.ColumnType);
                }

                var maxLength = property.GetMaxLength();
                if (maxLength.HasValue)
                {
                    lines.Add(
                        $".{nameof(PropertyBuilder.HasMaxLength)}({_code.Literal(maxLength.Value)})");
                }

                var precision = property.GetPrecision();
                var scale     = property.GetScale();
                if (precision != null && scale != null && scale != 0)
                {
                    lines.Add(
                        $".{nameof(PropertyBuilder.HasPrecision)}({_code.Literal(precision.Value)}, {_code.Literal(scale.Value)})");
                }
                else if (precision != null)
                {
                    lines.Add(
                        $".{nameof(PropertyBuilder.HasPrecision)}({_code.Literal(precision.Value)})");
                }

                if (property.IsUnicode() != null)
                {
                    lines.Add(
                        $".{nameof(PropertyBuilder.IsUnicode)}({(property.IsUnicode() == false ? "false" : "")})");
                }
            }

            if (property.TryGetDefaultValue(out var defaultValue))
            {
                if (defaultValue == DBNull.Value)
                {
                    lines.Add($".{nameof(RelationalPropertyBuilderExtensions.HasDefaultValue)}()");
                    annotations.Remove(RelationalAnnotationNames.DefaultValue);
                }
                else if (defaultValue != null)
                {
                    lines.Add(
                        $".{nameof(RelationalPropertyBuilderExtensions.HasDefaultValue)}({_code.UnknownLiteral(defaultValue)})");
                    annotations.Remove(RelationalAnnotationNames.DefaultValue);
                }
            }

            var valueGenerated = property.ValueGenerated;
            var isRowVersion   = false;

            if (((IConventionProperty)property).GetValueGeneratedConfigurationSource() is ConfigurationSource
                valueGeneratedConfigurationSource &&
                valueGeneratedConfigurationSource != ConfigurationSource.Convention &&
                ValueGenerationConvention.GetValueGenerated(property) != valueGenerated)
            {
                var methodName = valueGenerated switch
                {
                    ValueGenerated.OnAdd => nameof(PropertyBuilder.ValueGeneratedOnAdd),
                    ValueGenerated.OnAddOrUpdate => property.IsConcurrencyToken
                        ? nameof(PropertyBuilder.IsRowVersion)
                        : nameof(PropertyBuilder.ValueGeneratedOnAddOrUpdate),
                    ValueGenerated.OnUpdate => nameof(PropertyBuilder.ValueGeneratedOnUpdate),
                    ValueGenerated.Never => nameof(PropertyBuilder.ValueGeneratedNever),
                    _ => throw new InvalidOperationException(DesignStrings.UnhandledEnumValue($"{nameof(ValueGenerated)}.{valueGenerated}"))
                };

                lines.Add($".{methodName}()");
            }

            if (property.IsConcurrencyToken &&
                !isRowVersion)
            {
                lines.Add($".{nameof(PropertyBuilder.IsConcurrencyToken)}()");
            }

            lines.AddRange(
                _annotationCodeGenerator.GenerateFluentApiCalls(property, annotations).Select(m => _code.Fragment(m))
                .Concat(GenerateAnnotations(annotations.Values)));

            switch (lines.Count)
            {
            case 1:
                return;

            case 2:
                lines = new List <string> {
                    lines[0] + lines[1]
                };
                break;
            }

            AppendMultiLineFluentApi(property.DeclaringEntityType, lines);
        }
        /// <summary>
        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        public virtual ReverseEngineerFiles Generate(
            string connectionString,
            IEnumerable <string> tables,
            IEnumerable <string> schemas,
            string projectPath,
            string outputPath,
            string rootNamespace,
            string contextName,
            bool useDataAnnotations,
            bool overwriteFiles,
            bool useDatabaseNames)
        {
            Check.NotEmpty(connectionString, nameof(connectionString));
            Check.NotNull(tables, nameof(tables));
            Check.NotNull(schemas, nameof(schemas));
            Check.NotEmpty(projectPath, nameof(projectPath));
            Check.NotEmpty(rootNamespace, nameof(rootNamespace));

            if (!string.IsNullOrWhiteSpace(contextName) &&
                (!_cSharpUtilities.IsValidIdentifier(contextName) ||
                 _cSharpUtilities.IsCSharpKeyword(contextName)))
            {
                throw new ArgumentException(
                          DesignStrings.ContextClassNotValidCSharpIdentifier(contextName));
            }

            var databaseModel = _databaseModelFactory.Create(connectionString, tables, schemas);
            var model         = _factory.Create(databaseModel, useDatabaseNames);

            if (model == null)
            {
                throw new InvalidOperationException(
                          DesignStrings.ProviderReturnedNullModel(
                              _factory.GetType().ShortDisplayName()));
            }

            outputPath = string.IsNullOrWhiteSpace(outputPath) ? null : outputPath;
            var subNamespace = SubnamespaceFromOutputPath(projectPath, outputPath);

            var @namespace = rootNamespace;

            if (!string.IsNullOrEmpty(subNamespace))
            {
                @namespace += "." + subNamespace;
            }

            if (string.IsNullOrEmpty(contextName))
            {
                contextName = DefaultDbContextName;

                var annotatedName = model.Scaffolding().DatabaseName;
                if (!string.IsNullOrEmpty(annotatedName))
                {
                    contextName = _cSharpUtilities.GenerateCSharpIdentifier(
                        annotatedName + DbContextSuffix,
                        existingIdentifiers: null,
                        singularizePluralizer: null);
                }
            }

            CheckOutputFiles(outputPath ?? projectPath, contextName, model, overwriteFiles);

            return(ScaffoldingCodeGenerator.WriteCode(model, outputPath ?? projectPath, @namespace, contextName, connectionString, useDataAnnotations));
        }
        /// <summary>
        ///     <para>Initializes a new instance of the <see cref="OperationExecutor" /> class.</para>
        ///     <para>The arguments supported by <paramref name="args" /> are:</para>
        ///     <para><c>targetName</c>--The assembly name of the target project.</para>
        ///     <para><c>startupTargetName</c>--The assembly name of the startup project.</para>
        ///     <para><c>projectDir</c>--The target project's root directory.</para>
        ///     <para><c>rootNamespace</c>--The target project's root namespace.</para>
        /// </summary>
        /// <param name="reportHandler"> The <see cref="IOperationReportHandler" />. </param>
        /// <param name="args"> The executor arguments. </param>
        public OperationExecutor([NotNull] object reportHandler, [NotNull] IDictionary args)
        {
            Check.NotNull(reportHandler, nameof(reportHandler));
            Check.NotNull(args, nameof(args));

            var unwrappedReportHandler = ForwardingProxy.Unwrap <IOperationReportHandler>(reportHandler);
            var reporter = new OperationReporter(unwrappedReportHandler);

            var targetName        = (string)args["targetName"];
            var startupTargetName = (string)args["startupTargetName"];

            _projectDir = (string)args["projectDir"];
            var rootNamespace = (string)args["rootNamespace"];
            var language      = (string)args["language"];
            var toolsVersion  = (string)args["toolsVersion"];

            // TODO: Flow in from tools (issue #8332)
            var designArgs = Array.Empty <string>();

            var runtimeVersion = ProductInfo.GetVersion();

            if (toolsVersion != null &&
                new SemanticVersionComparer().Compare(toolsVersion, runtimeVersion) < 0)
            {
                reporter.WriteWarning(DesignStrings.VersionMismatch(toolsVersion, runtimeVersion));
            }

            // NOTE: LazyRef is used so any exceptions get passed to the resultHandler
            var startupAssembly = new LazyRef <Assembly>(
                () => Assembly.Load(new AssemblyName(startupTargetName)));
            var assembly = new LazyRef <Assembly>(
                () =>
            {
                try
                {
                    return(Assembly.Load(new AssemblyName(targetName)));
                }
                catch (Exception ex)
                {
                    throw new OperationException(
                        DesignStrings.UnreferencedAssembly(targetName, startupTargetName),
                        ex);
                }
            });

            _contextOperations = new LazyRef <DbContextOperations>(
                () => new DbContextOperations(
                    reporter,
                    assembly.Value,
                    startupAssembly.Value,
                    designArgs));
            _databaseOperations = new LazyRef <DatabaseOperations>(
                () => new DatabaseOperations(
                    reporter,
                    startupAssembly.Value,
                    _projectDir,
                    rootNamespace,
                    language,
                    designArgs));
            _migrationsOperations = new LazyRef <MigrationsOperations>(
                () => new MigrationsOperations(
                    reporter,
                    assembly.Value,
                    startupAssembly.Value,
                    _projectDir,
                    rootNamespace,
                    language,
                    designArgs));
        }
        /// <summary>
        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        public virtual ScaffoldedModel ScaffoldModel(
            string connectionString,
            IEnumerable <string> tables,
            IEnumerable <string> schemas,
            string @namespace,
            string language,
            string contextDir,
            string contextName,
            ModelReverseEngineerOptions modelOptions,
            ModelCodeGenerationOptions codeOptions)
        {
            Check.NotEmpty(connectionString, nameof(connectionString));
            Check.NotNull(tables, nameof(tables));
            Check.NotNull(schemas, nameof(schemas));
            Check.NotEmpty(@namespace, nameof(@namespace));
            Check.NotNull(language, nameof(language));
            Check.NotNull(modelOptions, nameof(modelOptions));
            Check.NotNull(codeOptions, nameof(codeOptions));

            if (!string.IsNullOrWhiteSpace(contextName) &&
                (!_cSharpUtilities.IsValidIdentifier(contextName) ||
                 _cSharpUtilities.IsCSharpKeyword(contextName)))
            {
                throw new ArgumentException(
                          DesignStrings.ContextClassNotValidCSharpIdentifier(contextName));
            }

            var resolvedConnectionString = _connectionStringResolver.ResolveConnectionString(connectionString);

            if (resolvedConnectionString != connectionString)
            {
                codeOptions.SuppressConnectionStringWarning = true;
            }

            var databaseModel = _databaseModelFactory.Create(resolvedConnectionString, tables, schemas);
            var model         = _factory.Create(databaseModel, modelOptions.UseDatabaseNames);

            if (model == null)
            {
                throw new InvalidOperationException(
                          DesignStrings.ProviderReturnedNullModel(
                              _factory.GetType().ShortDisplayName()));
            }

            if (string.IsNullOrEmpty(contextName))
            {
                contextName = DefaultDbContextName;

                var annotatedName = model.Scaffolding().DatabaseName;
                if (!string.IsNullOrEmpty(annotatedName))
                {
                    contextName = _cSharpUtilities.GenerateCSharpIdentifier(
                        annotatedName + DbContextSuffix,
                        existingIdentifiers: null,
                        singularizePluralizer: null);
                }
            }

            var codeGenerator = ModelCodeGeneratorSelector.Select(language);

            return(codeGenerator.GenerateModel(model, @namespace, contextDir ?? string.Empty, contextName, connectionString, codeOptions));
        }
        public virtual ScaffoldedModel ScaffoldModel(
            string connectionString,
            DatabaseModelFactoryOptions databaseOptions,
            ModelReverseEngineerOptions modelOptions,
            ModelCodeGenerationOptions codeOptions)
        {
            Check.NotEmpty(connectionString, nameof(connectionString));
            Check.NotNull(databaseOptions, nameof(databaseOptions));
            Check.NotNull(modelOptions, nameof(modelOptions));
            Check.NotNull(codeOptions, nameof(codeOptions));

            if (!string.IsNullOrWhiteSpace(codeOptions.ContextName) &&
                (!_cSharpUtilities.IsValidIdentifier(codeOptions.ContextName) ||
                 _cSharpUtilities.IsCSharpKeyword(codeOptions.ContextName)))
            {
                throw new ArgumentException(
                          DesignStrings.ContextClassNotValidCSharpIdentifier(codeOptions.ContextName));
            }

            var resolvedConnectionString = _connectionStringResolver.ResolveConnectionString(connectionString);

            if (resolvedConnectionString != connectionString)
            {
                codeOptions.SuppressConnectionStringWarning = true;
            }
            else if (!codeOptions.SuppressOnConfiguring)
            {
                _reporter.WriteWarning(DesignStrings.SensitiveInformationWarning);
            }

            if (codeOptions.ConnectionString == null)
            {
                codeOptions.ConnectionString = connectionString;
            }

            var databaseModel         = _databaseModelFactory.Create(resolvedConnectionString, databaseOptions);
            var modelConnectionString = (string?)(databaseModel[ScaffoldingAnnotationNames.ConnectionString]);

            if (!string.IsNullOrEmpty(modelConnectionString))
            {
                codeOptions.ConnectionString = modelConnectionString;
                databaseModel.RemoveAnnotation(ScaffoldingAnnotationNames.ConnectionString);
            }

            var model = _factory.Create(databaseModel, modelOptions);

            if (model == null)
            {
                throw new InvalidOperationException(
                          DesignStrings.ProviderReturnedNullModel(
                              _factory.GetType().ShortDisplayName()));
            }

            if (string.IsNullOrEmpty(codeOptions.ContextName))
            {
                var annotatedName = model.GetDatabaseName();
                codeOptions.ContextName = !string.IsNullOrEmpty(annotatedName)
                    ? _code.Identifier(annotatedName + DbContextSuffix)
                    : DefaultDbContextName;
            }

            var codeGenerator = ModelCodeGeneratorSelector.Select(codeOptions.Language);

            return(codeGenerator.GenerateModel(model, codeOptions));
        }