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 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);
        }