/// <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>
        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(""));

                    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);
        }
        /// <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>
        protected virtual IndexBuilder VisitUniqueConstraint([NotNull] EntityTypeBuilder builder, [NotNull] DatabaseUniqueConstraint uniqueConstraint)
        {
            Check.NotNull(builder, nameof(builder));
            Check.NotNull(uniqueConstraint, nameof(uniqueConstraint));

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

            if (unmappedColumns.Count > 0)
            {
                _reporter.WriteWarning(
                    DesignStrings.UnableToScaffoldIndexMissingProperty(
                        uniqueConstraint.Name,
                        string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator, unmappedColumns)));
                return(null);
            }

            var propertyNames = uniqueConstraint.Columns.Select(GetPropertyName).ToArray();
            var indexBuilder  = builder.HasIndex(propertyNames).IsUnique();

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

            indexBuilder.Metadata.AddAnnotations(uniqueConstraint.GetAnnotations());

            return(indexBuilder);
        }
        private void NameConstraintsCalled(object sender, EventArgs e)
        {
            var dte = (DTE)GetService(typeof(DTE));

            if (null == dte || dte.ActiveDocument == null)
            {
                return;
            }

            var doc = dte.ActiveDocument.Object("TextDocument") as TextDocument;

            if (null == doc)
            {
                return;
            }

            var ep = doc.StartPoint.CreateEditPoint();

            ep.EndOfDocument();

            var length = ep.AbsoluteCharOffset;

            ep.StartOfDocument();

            var originalText = ep.GetText(length);

            var namer        = new ConstraintNamer(originalText);
            var modifiedText = namer.Go();

            if (originalText != modifiedText)
            {
                ep.Delete(length);
                ep.Insert(modifiedText);
            }
        }
Пример #4
0
        private static string Uniquify <T>(string baseIdentifier, string prefix, Dictionary <string, T> existingIdentifiers, int maxLength)
        {
            if (!string.IsNullOrEmpty(prefix) &&
                !baseIdentifier.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
            {
                baseIdentifier = prefix + "_" + baseIdentifier;
            }

            var finalIdentifier = ConstraintNamer.Truncate(baseIdentifier, null, maxLength);
            var suffix          = 1;

            while (existingIdentifiers.ContainsKey(finalIdentifier))
            {
                finalIdentifier = ConstraintNamer.Truncate(baseIdentifier, suffix++, maxLength);
            }

            return(finalIdentifier);
        }
        /// <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>
        protected virtual IndexBuilder VisitIndex(EntityTypeBuilder builder, DatabaseIndex index)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }
            if (index == null)
            {
                throw new ArgumentNullException(nameof(index));
            }

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

            if (unmappedColumns.Any())
            {
                _reporter.WriteWarning(
                    DesignStrings.UnableToScaffoldIndexMissingProperty(
                        index.Name,
                        string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator, unmappedColumns)));
                return(null);
            }

            var propertyNames = index.Columns.Select(GetPropertyName).ToArray();
            var indexBuilder  = builder.HasIndex(propertyNames)
                                .IsUnique(index.IsUnique);

            if (index.Filter != null)
            {
                indexBuilder.HasFilter(index.Filter);
            }

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

            indexBuilder.Metadata.AddAnnotations(index.GetAnnotations());

            return(indexBuilder);
        }
        private void GenerateKeyAttribute(IProperty property)
        {
            var key = property.AsProperty().PrimaryKey;

            if (key?.Properties.Count == 1)
            {
                if (key is Key concreteKey &&
                    key.Properties.SequenceEqual(new KeyDiscoveryConvention(null).DiscoverKeyProperties(concreteKey.DeclaringEntityType, concreteKey.DeclaringEntityType.GetProperties().ToList())))
                {
                    return;
                }

                if (key.Relational().Name != ConstraintNamer.GetDefaultName(key))
                {
                    return;
                }

                _sb.AppendLine(new AttributeWriter(nameof(KeyAttribute)));
            }
        }
        private void NameConstraintsCalled(object sender, EventArgs e)
        {
            try
            {
                CallWrapper();

                var dte = (DTE)GetService(typeof(DTE));
                if (null == dte || dte.ActiveDocument == null)
                {
                    return;
                }

                var doc = dte.ActiveDocument.Object("TextDocument") as TextDocument;
                if (null == doc)
                {
                    return;
                }

                var ep = doc.StartPoint.CreateEditPoint();

                ep.EndOfDocument();

                var length = ep.AbsoluteCharOffset;
                ep.StartOfDocument();

                var originalText = ep.GetText(length);

                var namer        = new ConstraintNamer(originalText);
                var modifiedText = namer.Go();

                if (originalText != modifiedText)
                {
                    ep.Delete(length);
                    ep.Insert(modifiedText);
                }
            }
            catch (Exception ex)
            {
                OutputPane.WriteMessage("Exception naming constraints, error: {0}", ex.Message);
            }
        }
Пример #8
0
        public void PrimaryKey()
        {
            var scriptPath = ".\\tableOne.sql";

            if (File.Exists(scriptPath))
            {
                File.Delete(scriptPath);
            }

            File.Copy("..\\..\\..\\ProjectWithConstraints\\TableOne.sql", scriptPath);


            //var namer = new ConstraintNamer(scriptPath,
            //    "..\\..\\..\\ProjectWithConstraints\\bin\\Release\\ProjectWithConstraints.dacpac");

            var namer = new ConstraintNamer(File.ReadAllText(scriptPath));

            var changedText = namer.Go();

            Assert.LessOrEqual(-1, changedText.IndexOf("[Id] INT NOT NULL PRIMARY KEY"), changedText);
            Assert.Greater(changedText.IndexOf("CONSTRAINT [PK_TableOne] PRIMARY KEY ([Id])", StringComparison.OrdinalIgnoreCase), -1, changedText);
        }
        private void GenerateKeyAttribute(IProperty property)
        {
            var key = property.AsProperty().PrimaryKey;

            if (key?.Properties.Count == 1)
            {
                if (key is Key concreteKey &&
                    key.Properties.SequenceEqual(new KeyDiscoveryConvention(null).DiscoverKeyProperties(concreteKey.DeclaringEntityType, concreteKey.DeclaringEntityType.GetProperties().ToList())))
                {
                    return;
                }

                if (key.Relational().Name != ConstraintNamer.GetDefaultName(key))
                {
                    return;
                }

                PropertyAnnotationsData.Add(new Dictionary <string, object>
                {
                    { "property-annotation", new AttributeWriter(nameof(KeyAttribute)) },
                });
            }
        }
        /// <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>
        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.GetOrAddForeignKey(
                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().Name = foreignKey.Name;
            }

            AssignOnDeleteAction(foreignKey, key);

            key.AddAnnotations(foreignKey.GetAnnotations());

            return(key);
        }
        private void GenerateKey(IKey key, bool useDataAnnotations)
        {
            if (key == null)
            {
                return;
            }

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

            var explicitName = key.Relational().Name != ConstraintNamer.GetDefaultName(key);

            RemoveAnnotation(ref annotations, RelationalAnnotationNames.Name);

            if (key.Properties.Count == 1 &&
                annotations.Count == 0)
            {
                if (key is Key concreteKey &&
                    key.Properties.SequenceEqual(
                        new KeyDiscoveryConvention(null).DiscoverKeyProperties(
                            concreteKey.DeclaringEntityType,
                            concreteKey.DeclaringEntityType.GetProperties().ToList())))
                {
                    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)}" +
                    $"({_code.Literal(key.Relational().Name)})");
            }

            var annotationsToRemove = new List <IAnnotation>();

            foreach (var annotation in annotations)
            {
                if (_annotationCodeGenerator.IsHandledByConvention(key, annotation))
                {
                    annotationsToRemove.Add(annotation);
                }
                else
                {
                    var methodCall = _annotationCodeGenerator.GenerateFluentApi(key, annotation);
                    var line       = methodCall == null
#pragma warning disable CS0618 // Type or member is obsolete
                        ? _annotationCodeGenerator.GenerateFluentApi(key, annotation, Language)
#pragma warning restore CS0618 // Type or member is obsolete
                        : _code.Fragment(methodCall);

                    if (line != null)
                    {
                        lines.Add(line);
                        annotationsToRemove.Add(annotation);
                    }
                }
            }

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

            AppendMultiLineFluentApi(key.DeclaringEntityType, lines);
        }
        private void GenerateKey(IKey key, bool useDataAnnotations, IndentedStringBuilder sb)
        {
            if (key == null)
            {
                return;
            }

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

            var explicitName = key.Relational().Name != ConstraintNamer.GetDefaultName(key);

            RemoveAnnotation(ref annotations, RelationalAnnotationNames.Name);

            if (key.Properties.Count == 1)
            {
                if (key is Key concreteKey &&
                    key.Properties.SequenceEqual(new KeyDiscoveryConvention().DiscoverKeyProperties(concreteKey.DeclaringEntityType, concreteKey.DeclaringEntityType.GetProperties().ToList())))
                {
                    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)}({CSharpUtilities.DelimitString(key.Relational().Name)})");
            }

            var annotationsToRemove = new List <IAnnotation>();

            foreach (var annotation in annotations)
            {
                if (_annotationCodeGenerator.IsHandledByConvention(key, annotation))
                {
                    annotationsToRemove.Add(annotation);
                }
                else
                {
                    var line = _annotationCodeGenerator.GenerateFluentApi(key, annotation, Language);

                    if (line != null)
                    {
                        lines.Add(line);
                        annotationsToRemove.Add(annotation);
                    }
                }
            }

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

            AppendMultiLineFluentApi(key.DeclaringEntityType, lines, sb);
        }