Example #1
0
        /// <summary>
        /// Generate OnConfiguring method.
        /// </summary>
        /// <param name="connectionString">Database connection string.</param>
        /// <param name="suppressConnectionStringWarning">Suppress connection string warning.</param>
        protected virtual void GenerateOnConfiguring(
            string connectionString,
            bool suppressConnectionStringWarning)
        {
            if (connectionString == null)
            {
                throw new ArgumentNullException(nameof(connectionString));
            }

            var sb = new IndentedStringBuilder();

            using (sb.Indent())
            {
                sb.IncrementIndent();
                sb.AppendLine("protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)");
                sb.AppendLine("{");

                using (sb.Indent())
                {
                    sb.AppendLine("if (!optionsBuilder.IsConfigured)");
                    sb.AppendLine("{");

                    if (HandlebarsScaffoldingOptions.IncludeConnectionString)
                    {
                        using (sb.Indent())
                        {
                            if (!suppressConnectionStringWarning)
                            {
                                sb.DecrementIndent()
                                .DecrementIndent()
                                .DecrementIndent()
                                .DecrementIndent()
                                .AppendLine("#warning " + DesignStrings.SensitiveInformationWarning)
                                .IncrementIndent()
                                .IncrementIndent()
                                .IncrementIndent()
                                .IncrementIndent();
                            }

                            sb.Append("optionsBuilder")
                            .Append(
                                ProviderConfigurationCodeGenerator != null
                                        ? CSharpHelper.Fragment(
                                    ProviderConfigurationCodeGenerator.GenerateUseProvider(connectionString, null))
#pragma warning disable CS0618 // Type or member is obsolete
                                    : LegacyProviderCodeGenerator.GenerateUseProvider(connectionString, Language))
#pragma warning restore CS0618 // Type or member is obsolete
                            .AppendLine(";");
                        }
                    }

                    sb.AppendLine("}");
                }
                sb.AppendLine("}");

                var onConfiguring = sb.ToString();
                TemplateData.Add("on-configuring", onConfiguring);
            }
        }
        /// <summary>
        /// Generate OnConfiguring method.
        /// </summary>
        /// <param name="connectionString">Database connection string.</param>
        /// <param name="suppressConnectionStringWarning">Suppress connection string warning.</param>
        protected override void GenerateOnConfiguring(string connectionString, bool suppressConnectionStringWarning)
        {
            Check.NotNull(connectionString, nameof(connectionString));

            var sb = new IndentedStringBuilder();

            using (sb.Indent())
                using (sb.Indent())
                {
                    sb.AppendLine("protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)");
                    sb.AppendLine("{");

                    using (sb.Indent())
                    {
                        sb.AppendLine("if (!optionsBuilder.IsConfigured)");
                        sb.AppendLine("{");

                        using (sb.Indent())
                        {
                            if (!suppressConnectionStringWarning)
                            {
                                sb.DecrementIndent()
                                .DecrementIndent()
                                .DecrementIndent()
                                .DecrementIndent()
                                .AppendLine("#warning " + DesignStrings.SensitiveInformationWarning)
                                .IncrementIndent()
                                .IncrementIndent()
                                .IncrementIndent()
                                .IncrementIndent();
                            }

                            sb.Append("optionsBuilder");

                            var useProviderCall = ProviderConfigurationCodeGenerator.GenerateUseProvider(
                                connectionString,
                                ProviderConfigurationCodeGenerator.GenerateProviderOptions());
                            var contextOptions = ProviderConfigurationCodeGenerator.GenerateContextOptions();
                            if (contextOptions != null)
                            {
                                useProviderCall = useProviderCall.Chain(contextOptions);
                            }

                            sb.Append(CSharpHelper.Fragment(useProviderCall))
                            .AppendLine(";");
                        }
                        sb.AppendLine("}");
                    }

                    sb.AppendLine("}");
                }

            var onConfiguring = sb.ToString();

            TemplateData.Add("on-configuring", onConfiguring);
        }
        private void GenerateIndex(IIndex index, IndentedStringBuilder sb)
        {
            var lines = new List <string>
            {
                $".{nameof(EntityTypeBuilder.HasIndex)}(e => {GenerateLambdaToKey(index.Properties, "e")})"
            };

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

            if (!string.IsNullOrEmpty((string)index[RelationalAnnotationNames.Name]))
            {
                lines.Add(
                    $".{nameof(RelationalIndexBuilderExtensions.HasName)}" +
                    $"({CSharpHelper.Literal(index.GetName())})");
                RemoveAnnotation(ref annotations, RelationalAnnotationNames.Name);
            }

            if (index.IsUnique)
            {
                lines.Add($".{nameof(IndexBuilder.IsUnique)}()");
            }

            if (index.GetFilter() != null)
            {
                lines.Add(
                    $".{nameof(RelationalIndexBuilderExtensions.HasFilter)}" +
                    $"({CSharpHelper.Literal(index.GetFilter())})");
                RemoveAnnotation(ref annotations, RelationalAnnotationNames.Filter);
            }

            var annotationsToRemove = new List <IAnnotation>();

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

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

            AppendMultiLineFluentApi(index.DeclaringEntityType, lines, sb);
        }
        private string GetOnConfiguring(string connectionString, bool suppressConnectionStringWarning)
        {
            var sb = new IndentedStringBuilder();

            using (sb.Indent())
                using (sb.Indent())
                {
                    sb.AppendLine("protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)");
                    sb.AppendLine("{");

                    using (sb.Indent())
                    {
                        sb.AppendLine("if (!optionsBuilder.IsConfigured)");
                        sb.AppendLine("{");

                        using (sb.Indent())
                        {
                            if (!suppressConnectionStringWarning)
                            {
                                sb.DecrementIndent()
                                .DecrementIndent()
                                .DecrementIndent()
                                .DecrementIndent()
                                .AppendLine("#warning " + DesignStrings.SensitiveInformationWarning)
                                .IncrementIndent()
                                .IncrementIndent()
                                .IncrementIndent()
                                .IncrementIndent();
                            }

                            sb.Append("optionsBuilder");

                            var useProviderCall = ProviderConfigurationCodeGenerator.GenerateUseProvider(connectionString);

                            sb.Append(CSharpHelper.Fragment(useProviderCall))
                            .AppendLine(";");
                        }
                        sb.AppendLine("}");
                    }

                    sb.AppendLine("}");
                }

            return(sb.ToString());
        }
        /// <summary>
        /// Generate OnConfiguring method.
        /// </summary>
        /// <param name="connectionString">Database connection string.</param>
        /// <param name="suppressConnectionStringWarning">Suppress connection string warning.</param>
        protected override void GenerateOnConfiguring([NotNull] string connectionString, bool suppressConnectionStringWarning)
        {
            Check.NotNull(connectionString, nameof(connectionString));

            var onConfiguring = GetOnConfiguring(connectionString, suppressConnectionStringWarning);

            TemplateData.Add("on-configuring", onConfiguring);

            TemplateData.Add("connection-string", connectionString);
            TemplateData.Add("connectionstring-warning", $"#warning {DesignStrings.SensitiveInformationWarning}");

            var useProviderCall = ProviderConfigurationCodeGenerator.GenerateUseProvider(
                connectionString, ProviderConfigurationCodeGenerator.GenerateProviderOptions());
            var contextOptions = ProviderConfigurationCodeGenerator.GenerateContextOptions();

            if (contextOptions != null)
            {
                useProviderCall = useProviderCall.Chain(contextOptions);
            }

            TemplateData.Add("options-builder-provider", CSharpHelper.Fragment(useProviderCall));
        }
        private void GenerateRelationship(IForeignKey foreignKey, bool useDataAnnotations, IndentedStringBuilder sb)
        {
            var canUseDataAnnotations = true;
            var annotations           = AnnotationCodeGenerator
                                        .FilterIgnoredAnnotations(foreignKey.GetAnnotations())
                                        .ToDictionary(a => a.Name, a => a);

            AnnotationCodeGenerator.RemoveAnnotationsHandledByConventions(foreignKey, annotations);

            var lines = new List <string>
            {
                $".{nameof(EntityTypeBuilder.HasOne)}("
                + (foreignKey.DependentToPrincipal != null ? $"d => d.{EntityTypeTransformationService.TransformNavPropertyName(foreignKey.DependentToPrincipal?.Name, foreignKey.PrincipalToDependent?.DeclaringType.Name)}" : null)
                + ")",
                $".{(foreignKey.IsUnique ? nameof(ReferenceNavigationBuilder.WithOne) : nameof(ReferenceNavigationBuilder.WithMany))}"
                + "("
                + (foreignKey.PrincipalToDependent != null ? $"p => p.{EntityTypeTransformationService.TransformNavPropertyName(foreignKey.PrincipalToDependent?.Name, foreignKey.DependentToPrincipal?.DeclaringType.Name)}" : null)
                + ")"
            };

            if (!foreignKey.PrincipalKey.IsPrimaryKey())
            {
                canUseDataAnnotations = false;
                lines.Add(
                    $".{nameof(ReferenceReferenceBuilder.HasPrincipalKey)}"
                    + (foreignKey.IsUnique ? $"<{EntityTypeTransformationService.TransformPropertyName(((ITypeBase)foreignKey.PrincipalEntityType).DisplayName(), "")}>" : "")
                    + $"(p => {GenerateLambdaToKey(foreignKey.PrincipalKey.Properties, "p", EntityTypeTransformationService.TransformNavPropertyName)})");
            }

            lines.Add(
                $".{nameof(ReferenceReferenceBuilder.HasForeignKey)}"
                + (foreignKey.IsUnique ? $"<{GetEntityTypeName(foreignKey.PrincipalEntityType, EntityTypeTransformationService.TransformTypeEntityName(((ITypeBase)foreignKey.DeclaringEntityType).DisplayName()))}>" : "")
                + $"(d => {GenerateLambdaToKey(foreignKey.Properties, "d", EntityTypeTransformationService.TransformPropertyName)})");

            var defaultOnDeleteAction = foreignKey.IsRequired
                ? DeleteBehavior.Cascade
                : DeleteBehavior.ClientSetNull;

            if (foreignKey.DeleteBehavior != defaultOnDeleteAction)
            {
                canUseDataAnnotations = false;
                lines.Add(
                    $".{nameof(ReferenceReferenceBuilder.OnDelete)}({CSharpHelper.Literal(foreignKey.DeleteBehavior)})");
            }

            if (!string.IsNullOrEmpty((string)foreignKey[RelationalAnnotationNames.Name]))
            {
                canUseDataAnnotations = false;
            }

            lines.AddRange(
                AnnotationCodeGenerator.GenerateFluentApiCalls(foreignKey, annotations).Select(m => CSharpHelper.Fragment(m))
                .Concat(GenerateAnnotations(annotations.Values)));

            if (!useDataAnnotations ||
                !canUseDataAnnotations)
            {
                AppendMultiLineFluentApi(foreignKey.DeclaringEntityType, lines, sb);
            }
        }
        private void GenerateProperty(IProperty property, bool useDataAnnotations, IndentedStringBuilder sb)
        {
            var lines = new List <string>
            {
                $".{nameof(EntityTypeBuilder.Property)}(e => e.{EntityTypeTransformationService.TransformPropertyName(property.Name, property.DeclaringType.Name)})"
            };

            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 (!property.IsNullable &&
                    property.ClrType.IsNullableType() &&
                    !property.IsPrimaryKey())
                {
                    lines.Add($".{nameof(PropertyBuilder.IsRequired)}()");
                }

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

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

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

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

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

            var defaultValue = property.GetDefaultValue();

            if (defaultValue == DBNull.Value)
            {
                lines.Add($".{nameof(RelationalPropertyBuilderExtensions.HasDefaultValue)}()");
                annotations.Remove(RelationalAnnotationNames.DefaultValue);
            }
            else if (defaultValue != null)
            {
                lines.Add(
                    $".{nameof(RelationalPropertyBuilderExtensions.HasDefaultValue)}({CSharpHelper.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 => CSharpHelper.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, sb);
        }
        private void GenerateIndex(IIndex index, IndentedStringBuilder sb)
        {
            var annotations = AnnotationCodeGenerator
                              .FilterIgnoredAnnotations(index.GetAnnotations())
                              .ToDictionary(a => a.Name, a => a);

            AnnotationCodeGenerator.RemoveAnnotationsHandledByConventions(index, annotations);

            var lines = new List <string>
            {
                $".{nameof(EntityTypeBuilder.HasIndex)}(e => {GenerateLambdaToKey(index.Properties, "e", EntityTypeTransformationService.TransformPropertyName)})"
            };

            annotations.Remove(RelationalAnnotationNames.Name);

            if (index.IsUnique)
            {
                lines.Add($".{nameof(IndexBuilder.IsUnique)}()");
            }

            lines.AddRange(
                AnnotationCodeGenerator.GenerateFluentApiCalls(index, annotations).Select(m => CSharpHelper.Fragment(m))
                .Concat(GenerateAnnotations(annotations.Values)));

            AppendMultiLineFluentApi(index.DeclaringEntityType, lines, sb);
        }
        private void GenerateKey(IKey key, IEntityType entityType, bool useDataAnnotations, IndentedStringBuilder sb)
        {
            if (key == null)
            {
                if (!useDataAnnotations)
                {
                    var line = new List <string> {
                        $".{nameof(EntityTypeBuilder.HasNoKey)}()"
                    };

                    AppendMultiLineFluentApi(entityType, line, sb);
                }

                return;
            }

            var annotations = AnnotationCodeGenerator
                              .FilterIgnoredAnnotations(key.GetAnnotations())
                              .ToDictionary(a => a.Name, a => a);

            AnnotationCodeGenerator.RemoveAnnotationsHandledByConventions(key, annotations);

            var explicitName = key.GetName() != key.GetDefaultName();

            annotations.Remove(RelationalAnnotationNames.Name);

            if (key.Properties.Count == 1 &&
                annotations.Count == 0)
            {
                if (key is Key concreteKey &&
                    key.Properties.SequenceEqual(
                        KeyDiscoveryConvention.DiscoverKeyProperties(
                            concreteKey.DeclaringEntityType,
                            concreteKey.DeclaringEntityType.GetProperties())))
                {
                    return;
                }

                if (!explicitName &&
                    useDataAnnotations)
                {
                    return;
                }
            }

            var lines = new List <string>
            {
                $".{nameof(EntityTypeBuilder.HasKey)}(e => {GenerateLambdaToKey(key.Properties, "e", EntityTypeTransformationService.TransformPropertyName)})"
            };

            if (explicitName)
            {
                lines.Add(
                    $".{nameof(RelationalKeyBuilderExtensions.HasName)}" +
                    $"({CSharpHelper.Literal(key.GetName())})");
            }

            lines.AddRange(
                AnnotationCodeGenerator.GenerateFluentApiCalls(key, annotations).Select(m => CSharpHelper.Fragment(m))
                .Concat(GenerateAnnotations(annotations.Values)));

            AppendMultiLineFluentApi(key.DeclaringEntityType, lines, sb);
        }
        private void GenerateEntityType(IEntityType entityType, bool useDataAnnotations, IndentedStringBuilder sb)
        {
            GenerateKey(entityType.FindPrimaryKey(), entityType, useDataAnnotations, sb);

            var annotations = AnnotationCodeGenerator
                              .FilterIgnoredAnnotations(entityType.GetAnnotations())
                              .ToDictionary(a => a.Name, a => a);

            AnnotationCodeGenerator.RemoveAnnotationsHandledByConventions(entityType, annotations);

            annotations.Remove(RelationalAnnotationNames.TableName);
            annotations.Remove(RelationalAnnotationNames.Schema);
            annotations.Remove(RelationalAnnotationNames.ViewName);
            annotations.Remove(RelationalAnnotationNames.ViewSchema);
            annotations.Remove(ScaffoldingAnnotationNames.DbSetName);
            annotations.Remove(RelationalAnnotationNames.ViewDefinitionSql);

            if (useDataAnnotations)
            {
                // Strip out any annotations handled as attributes - these are already handled when generating
                // the entity's properties
                _ = AnnotationCodeGenerator.GenerateDataAnnotationAttributes(entityType, annotations);
            }

            if (!useDataAnnotations || entityType.GetViewName() != null)
            {
                GenerateTableName(entityType, sb);
            }

            var lines = new List <string>(
                AnnotationCodeGenerator.GenerateFluentApiCalls(entityType, annotations).Select(m => CSharpHelper.Fragment(m))
                .Concat(GenerateAnnotations(annotations.Values)));

            AppendMultiLineFluentApi(entityType, lines, sb);

            foreach (var index in entityType.GetIndexes())
            {
                // If there are annotations that cannot be represented using an IndexAttribute then use fluent API even
                // if useDataAnnotations is true.
                var indexAnnotations = AnnotationCodeGenerator
                                       .FilterIgnoredAnnotations(index.GetAnnotations())
                                       .ToDictionary(a => a.Name, a => a);
                AnnotationCodeGenerator.RemoveAnnotationsHandledByConventions(index, indexAnnotations);

                if (!useDataAnnotations || indexAnnotations.Count > 0)
                {
                    GenerateIndex(index, sb);
                }
            }

            foreach (var property in entityType.GetProperties())
            {
                GenerateProperty(property, useDataAnnotations, sb);
            }

            foreach (var foreignKey in entityType.GetScaffoldForeignKeys(_options.Value))
            {
                GenerateRelationship(foreignKey, useDataAnnotations, sb);
            }
        }
        /// <summary>
        /// Generate OnModelBuilding method.
        /// </summary>
        /// <param name="model">Metadata about the shape of entities, the relationships between them, and how they map to the database.</param>
        /// <param name="useDataAnnotations">Use fluent modeling API if false.</param>
        protected override void GenerateOnModelCreating([NotNull] IModel model, bool useDataAnnotations)
        {
            Check.NotNull(model, nameof(model));

            var sb = new IndentedStringBuilder();

            using (sb.Indent())
                using (sb.Indent())
                {
                    sb.AppendLine("protected override void OnModelCreating(ModelBuilder modelBuilder)");
                    sb.Append("{");

                    var annotations = AnnotationCodeGenerator
                                      .FilterIgnoredAnnotations(model.GetAnnotations())
                                      .ToDictionary(a => a.Name, a => a);

                    AnnotationCodeGenerator.RemoveAnnotationsHandledByConventions(model, annotations);

                    annotations.Remove(CoreAnnotationNames.ProductVersion);
                    annotations.Remove(RelationalAnnotationNames.MaxIdentifierLength);
                    annotations.Remove(ScaffoldingAnnotationNames.DatabaseName);
                    annotations.Remove(ScaffoldingAnnotationNames.EntityTypeErrors);

                    var lines = new List <string>();

                    lines.AddRange(
                        AnnotationCodeGenerator.GenerateFluentApiCalls(model, annotations).Select(m => CSharpHelper.Fragment(m))
                        .Concat(GenerateAnnotations(annotations.Values)));

                    if (lines.Count > 0)
                    {
                        using (sb.Indent())
                        {
                            sb.AppendLine();
                            sb.Append("modelBuilder" + lines[0]);

                            using (sb.Indent())
                            {
                                foreach (var line in lines.Skip(1))
                                {
                                    sb.AppendLine();
                                    sb.Append(line);
                                }
                            }

                            sb.AppendLine(";");
                        }
                    }

                    using (sb.Indent())
                    {
                        foreach (var entityType in model.GetScaffoldEntityTypes(_options.Value))
                        {
                            _entityTypeBuilderInitialized = false;

                            GenerateEntityType(entityType, useDataAnnotations, sb);

                            if (_entityTypeBuilderInitialized)
                            {
                                sb.AppendLine("});");
                            }
                        }

                        foreach (var sequence in model.GetSequences())
                        {
                            GenerateSequence(sequence, sb);
                        }
                    }

                    sb.AppendLine();
                    using (sb.Indent())
                    {
                        sb.AppendLine("OnModelCreatingPartial(modelBuilder);");
                    }
                    sb.AppendLine("}");
                    sb.AppendLine();
                    sb.Append("partial void OnModelCreatingPartial(ModelBuilder modelBuilder);");
                }

            var onModelCreating = sb.ToString();

            TemplateData.Add("on-model-creating", onModelCreating);
        }
        private void GenerateRelationship(IForeignKey foreignKey, bool useDataAnnotations, IndentedStringBuilder sb)
        {
            var canUseDataAnnotations = true;
            var annotations           = foreignKey.GetAnnotations().ToList();

            var lines = new List <string>
            {
                $".{nameof(EntityTypeBuilder.HasOne)}(" + (foreignKey.DependentToPrincipal != null ? $"d => d.{foreignKey.DependentToPrincipal.Name}" : null) + ")",
                $".{(foreignKey.IsUnique ? nameof(ReferenceNavigationBuilder.WithOne) : nameof(ReferenceNavigationBuilder.WithMany))}"
                + $"(" + (foreignKey.PrincipalToDependent != null ? $"p => p.{foreignKey.PrincipalToDependent.Name}" : null) + ")"
            };

            if (!foreignKey.PrincipalKey.IsPrimaryKey())
            {
                canUseDataAnnotations = false;
                lines.Add(
                    $".{nameof(ReferenceReferenceBuilder.HasPrincipalKey)}"
                    + (foreignKey.IsUnique ? $"<{((ITypeBase)foreignKey.PrincipalEntityType).DisplayName()}>" : "")
                    + $"(p => {GenerateLambdaToKey(foreignKey.PrincipalKey.Properties, "p")})");
            }

            lines.Add(
                $".{nameof(ReferenceReferenceBuilder.HasForeignKey)}"
                + (foreignKey.IsUnique ? $"<{((ITypeBase)foreignKey.DeclaringEntityType).DisplayName()}>" : "")
                + $"(d => {GenerateLambdaToKey(foreignKey.Properties, "d")})");

            var defaultOnDeleteAction = foreignKey.IsRequired
                ? DeleteBehavior.Cascade
                : DeleteBehavior.ClientSetNull;

            if (foreignKey.DeleteBehavior != defaultOnDeleteAction)
            {
                canUseDataAnnotations = false;
                lines.Add(
                    $".{nameof(ReferenceReferenceBuilder.OnDelete)}" +
                    $"({CSharpHelper.Literal(foreignKey.DeleteBehavior)})");
            }

            if (!string.IsNullOrEmpty((string)foreignKey[RelationalAnnotationNames.Name]))
            {
                canUseDataAnnotations = false;
                lines.Add(
                    $".HasConstraintName" +
                    $"({CSharpHelper.Literal(foreignKey.GetConstraintName())})");
                RemoveAnnotation(ref annotations, RelationalAnnotationNames.Name);
            }

            var annotationsToRemove = new List <IAnnotation>();

            foreach (var annotation in annotations)
            {
                if (annotation.Value == null ||
                    AnnotationCodeGenerator.IsHandledByConvention(foreignKey, annotation))
                {
                    annotationsToRemove.Add(annotation);
                }
                else
                {
                    var methodCall = AnnotationCodeGenerator.GenerateFluentApi(foreignKey, annotation);
                    if (methodCall != null)
                    {
                        canUseDataAnnotations = false;
                        lines.Add(CSharpHelper.Fragment(methodCall));
                        annotationsToRemove.Add(annotation);
                    }
                }
            }

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

            if (!useDataAnnotations ||
                !canUseDataAnnotations)
            {
                AppendMultiLineFluentApi(foreignKey.DeclaringEntityType, lines, sb);
            }
        }
        private void GenerateProperty(IProperty property, bool useDataAnnotations, IndentedStringBuilder sb)
        {
            var lines = new List <string>
            {
                $".{nameof(EntityTypeBuilder.Property)}(e => e.{property.Name})"
            };

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

            RemoveAnnotation(ref annotations, RelationalAnnotationNames.ColumnName);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.ColumnType);
            RemoveAnnotation(ref annotations, CoreAnnotationNames.MaxLength);
            RemoveAnnotation(ref annotations, CoreAnnotationNames.TypeMapping);
            RemoveAnnotation(ref annotations, CoreAnnotationNames.Unicode);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.DefaultValue);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.DefaultValueSql);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.Comment);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.ComputedColumnSql);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.IsFixedLength);
            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)}" +
                        $"({CSharpHelper.Literal(columnName)})");
                }

                var columnType = property.GetConfiguredColumnType();

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

                var maxLength = property.GetMaxLength();

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

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

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

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

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

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

            if (property.GetComputedColumnSql() != null)
            {
                lines.Add(
                    $".{nameof(RelationalPropertyBuilderExtensions.HasComputedColumnSql)}" +
                    $"({CSharpHelper.Literal(property.GetComputedColumnSql())})");
            }

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

            if (((IConventionProperty)property).GetValueGeneratedConfigurationSource().HasValue &&
                RelationalValueGenerationConvention.GetValueGenerated(property) != valueGenerated)
            {
                string methodName;
                switch (valueGenerated)
                {
                case ValueGenerated.OnAdd:
                    methodName = nameof(PropertyBuilder.ValueGeneratedOnAdd);
                    break;

                case ValueGenerated.OnAddOrUpdate:
                    isRowVersion = property.IsConcurrencyToken;
                    methodName   = isRowVersion
                            ? nameof(PropertyBuilder.IsRowVersion)
                            : nameof(PropertyBuilder.ValueGeneratedOnAddOrUpdate);
                    break;

                case ValueGenerated.Never:
                    methodName = nameof(PropertyBuilder.ValueGeneratedNever);
                    break;

                default:
                    methodName = "";
                    break;
                }

                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(CSharpHelper.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, sb);
        }
        private void GenerateKey(IKey key, IEntityType entityType, bool useDataAnnotations, IndentedStringBuilder sb)
        {
            if (key == null)
            {
                var line = new List <string>
                {
                    $".{nameof(EntityTypeBuilder.HasNoKey)}()"
                };

                AppendMultiLineFluentApi(entityType, line, sb);

                return;
            }

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

            var explicitName = key.GetName() != key.GetDefaultName();

            RemoveAnnotation(ref annotations, RelationalAnnotationNames.Name);

            if (key.Properties.Count == 1 &&
                annotations.Count == 0)
            {
                if (key is Key concreteKey &&
                    key.Properties.SequenceEqual(
                        KeyDiscoveryConvention.DiscoverKeyProperties(
                            concreteKey.DeclaringEntityType,
                            concreteKey.DeclaringEntityType.GetProperties())))
                {
                    return;
                }

                if (!explicitName &&
                    useDataAnnotations)
                {
                    return;
                }
            }

            var lines = new List <string>
            {
                $".{nameof(EntityTypeBuilder.HasKey)}(e => {GenerateLambdaToKey(key.Properties, "e")})"
            };

            if (explicitName)
            {
                lines.Add(
                    $".{nameof(RelationalKeyBuilderExtensions.HasName)}" +
                    $"({CSharpHelper.Literal(key.GetName())})");
            }

            var annotationsToRemove = new List <IAnnotation>();

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

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

            AppendMultiLineFluentApi(key.DeclaringEntityType, lines, sb);
        }
        private void GenerateEntityType(IEntityType entityType, bool useDataAnnotations, IndentedStringBuilder sb)
        {
            GenerateKey(entityType.FindPrimaryKey(), entityType, useDataAnnotations, sb);

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

            RemoveAnnotation(ref annotations, CoreAnnotationNames.ConstructorBinding);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.TableName);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.Comment);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames.Schema);
            RemoveAnnotation(ref annotations, ScaffoldingAnnotationNames.DbSetName);
            RemoveAnnotation(ref annotations, RelationalAnnotationNames2.ViewDefinition);

            var isView = entityType.FindAnnotation(RelationalAnnotationNames2.ViewDefinition) != null;

            if (!useDataAnnotations || isView)
            {
                GenerateTableName(entityType, sb);
            }

            var annotationsToRemove = new List <IAnnotation>();
            var lines = new List <string>();

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

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

            if (entityType.GetComment() != null)
            {
                lines.Add(
                    $".{nameof(RelationalEntityTypeBuilderExtensions.HasComment)}" +
                    $"({CSharpHelper.Literal(entityType.GetComment())})");
            }

            AppendMultiLineFluentApi(entityType, lines, sb);

            foreach (var index in entityType.GetIndexes())
            {
                GenerateIndex(index, sb);
            }

            foreach (var property in entityType.GetProperties())
            {
                GenerateProperty(property, useDataAnnotations, sb);
            }

            foreach (var foreignKey in entityType.GetScaffoldForeignKeys(_options.Value))
            {
                GenerateRelationship(foreignKey, useDataAnnotations, sb);
            }
        }
        /// <summary>
        /// Generate OnModelBuilding method.
        /// </summary>
        /// <param name="model">Metadata about the shape of entities, the relationships between them, and how they map to the database.</param>
        /// <param name="useDataAnnotations">Use fluent modeling API if false.</param>
        protected override void GenerateOnModelCreating(IModel model, bool useDataAnnotations)
        {
            Check.NotNull(model, nameof(model));

            var sb = new IndentedStringBuilder();

            using (sb.Indent())
                using (sb.Indent())
                {
                    sb.AppendLine("protected override void OnModelCreating(ModelBuilder modelBuilder)");
                    sb.Append("{");

                    var annotations = model.GetAnnotations().ToList();
                    RemoveAnnotation(ref annotations, CoreAnnotationNames.ProductVersion);
                    RemoveAnnotation(ref annotations, CoreAnnotationNames.ChangeTrackingStrategy);
                    RemoveAnnotation(ref annotations, CoreAnnotationNames.OwnedTypes);
                    RemoveAnnotation(ref annotations, ChangeDetector.SkipDetectChangesAnnotation);
                    RemoveAnnotation(ref annotations, RelationalAnnotationNames.MaxIdentifierLength);
                    RemoveAnnotation(ref annotations, RelationalAnnotationNames.CheckConstraints);
                    RemoveAnnotation(ref annotations, ScaffoldingAnnotationNames.DatabaseName);
                    RemoveAnnotation(ref annotations, ScaffoldingAnnotationNames.EntityTypeErrors);

                    var annotationsToRemove = new List <IAnnotation>();
                    annotationsToRemove.AddRange(
                        annotations.Where(
                            a => a.Name.StartsWith(RelationalAnnotationNames.SequencePrefix, StringComparison.Ordinal)));

                    var lines = new List <string>();

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

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

                    if (lines.Count > 0)
                    {
                        using (sb.Indent())
                        {
                            sb.AppendLine();
                            sb.Append("modelBuilder" + lines[0]);

                            using (sb.Indent())
                            {
                                foreach (var line in lines.Skip(1))
                                {
                                    sb.AppendLine();
                                    sb.Append(line);
                                }
                            }

                            sb.AppendLine(";");
                        }
                    }

                    using (sb.Indent())
                    {
                        foreach (var entityType in model.GetScaffoldEntityTypes(_options.Value))
                        {
                            _entityTypeBuilderInitialized = false;

                            GenerateEntityType(entityType, useDataAnnotations, sb);

                            if (_entityTypeBuilderInitialized)
                            {
                                sb.AppendLine("});");
                            }
                        }

                        foreach (var sequence in model.GetSequences())
                        {
                            GenerateSequence(sequence, sb);
                        }
                    }

                    sb.AppendLine();
                    using (sb.Indent())
                    {
                        sb.AppendLine("OnModelCreatingPartial(modelBuilder);");
                    }
                    sb.AppendLine("}");
                    sb.AppendLine();
                    sb.Append("partial void OnModelCreatingPartial(ModelBuilder modelBuilder);");
                }

            var onModelCreating = sb.ToString();

            TemplateData.Add("on-model-creating", onModelCreating);
        }