/// <summary>
        /// Generate entity type data annotations.
        /// </summary>
        /// <param name="entityType">Represents an entity type in an <see cref="T:Microsoft.EntityFrameworkCore.Metadata.IModel" />.</param>
        protected override void GenerateEntityTypeDataAnnotations(IEntityType entityType)
        {
            Check.NotNull(entityType, nameof(entityType));

            //GenerateTableAttribute(entityType);

            ClassAnnotationsData = new List <Dictionary <string, object> >();

            GenerateKeylessAttribute(entityType);
            GenerateTableAttribute(entityType);
            GenerateIndexAttributes(entityType);

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

            AnnotationCodeGenerator.RemoveAnnotationsHandledByConventions(entityType, annotations);

            foreach (var attribute in AnnotationCodeGenerator.GenerateDataAnnotationAttributes(entityType, annotations))
            {
                var attributeWriter = new AttributeWriter(attribute.Type.Name);
                foreach (var argument in attribute.Arguments)
                {
                    attributeWriter.AddParameter(CSharpHelper.UnknownLiteral(argument));
                }
            }

            TemplateData.Add("class-annotations", ClassAnnotationsData);
        }
        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 property data annotations.
        /// </summary>
        /// <param name="property">Represents a scalar property of an entity.</param>
        protected override void GeneratePropertyDataAnnotations(IProperty property)
        {
            Check.NotNull(property, nameof(property));

            GenerateKeyAttribute(property);
            GenerateRequiredAttribute(property);
            GenerateColumnAttribute(property);
            GenerateMaxLengthAttribute(property);

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

            AnnotationCodeGenerator.RemoveAnnotationsHandledByConventions(property, annotations);

            foreach (var attribute in AnnotationCodeGenerator.GenerateDataAnnotationAttributes(property, annotations))
            {
                var attributeWriter = new AttributeWriter(attribute.Type.Name);
                foreach (var argument in attribute.Arguments)
                {
                    attributeWriter.AddParameter(CSharpHelper.UnknownLiteral(argument));
                }
            }
        }
        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);
        }