Exemplo n.º 1
0
        public virtual void CheckSelectionsMatched([NotNull] TableSelectionSet tableSelectionSet)
        {
            foreach (var schemaSelection in tableSelectionSet.Schemas.Where(s => !s.IsMatched))
            {
                Logger.LogWarning(
                    RelationalDesignEventId.MissingSchemaWarning,
                    () => RelationalDesignStrings.MissingSchema(schemaSelection.Text));
            }

            foreach (var tableSelection in tableSelectionSet.Tables.Where(t => !t.IsMatched))
            {
                Logger.LogWarning(
                    RelationalDesignEventId.MissingTableWarning,
                    () => RelationalDesignStrings.MissingTable(tableSelection.Text));
            }
        }
Exemplo n.º 2
0
        public async Task Principal_missing_primary_key()
        {
            using (var testStore = SqliteTestStore.GetOrCreateShared("NoPrincipalPk" + DbSuffix))
            {
                testStore.ExecuteNonQuery(@"CREATE TABLE IF NOT EXISTS Dependent (
    Id PRIMARY KEY,
    PrincipalId INT,
    FOREIGN KEY (PrincipalId) REFERENCES Principal(Id)
);
CREATE TABLE IF NOT EXISTS Principal ( Id INT);");

                var results = await Generator.GenerateAsync(new ReverseEngineeringConfiguration
                {
                    ConnectionString     = testStore.ConnectionString,
                    ProjectPath          = TestProjectPath,
                    ProjectRootNamespace = "E2E.Sqlite",
                    UseFluentApiOnly     = UseFluentApiOnly,
                    TableSelectionSet    = TableSelectionSet.All
                });

                var expectedLog = new LoggerMessages
                {
                    Warn =
                    {
                        RelationalDesignStrings.MissingPrimaryKey("Principal"),
                        RelationalDesignStrings.UnableToGenerateEntityType("Principal"),
                        RelationalDesignStrings.ForeignKeyScaffoldErrorPrincipalTableScaffoldingError("Dependent(PrincipalId)", "Principal")
                    }
                };
                AssertLog(expectedLog);

                var expectedFileSet = new FileSet(new FileSystemFileService(), Path.Combine(ExpectedResultsParentDir, "NoPrincipalPk"))
                {
                    Files =
                    {
                        "NoPrincipalPk" + DbSuffix + "Context.expected",
                        "Dependent.expected"
                    }
                };
                var actualFileSet = new FileSet(InMemoryFiles, TestProjectFullPath)
                {
                    Files = Enumerable.Repeat(results.ContextFile, 1).Concat(results.EntityTypeFiles).Select(Path.GetFileName).ToList()
                };
                AssertEqualFileContents(expectedFileSet, actualFileSet);
                AssertCompile(actualFileSet);
            }
        }
Exemplo n.º 3
0
        public void E2ETest_AllFluentApi()
        {
            var configuration = new ReverseEngineeringConfiguration
            {
                ConnectionString     = _connectionString,
                ProjectPath          = TestProjectDir,
                ProjectRootNamespace = TestNamespace,
                OutputPath           = null, // not used for this test
                UseFluentApiOnly     = true,
                TableSelectionSet    = Filter
            };

            var filePaths = Generator.GenerateAsync(configuration).GetAwaiter().GetResult();

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

            var expectedFileSet = new FileSet(new FileSystemFileService(),
                                              Path.Combine("ReverseEngineering", "Expected", "AllFluentApi"),
                                              inputFile => inputFile.Replace("{{connectionString}}", _connectionString))
            {
                Files = new List <string> {
                    "SqlServerReverseEngineerTestE2EContext.expected"
                }
                .Concat(_expectedEntityTypeFiles).ToList()
            };

            AssertLog(new LoggerMessages
            {
                Warn =
                {
                    RelationalDesignStrings.CannotFindTypeMappingForColumn("dbo.AllDataTypes.geographyColumn",                                              "geography"),
                    RelationalDesignStrings.CannotFindTypeMappingForColumn("dbo.AllDataTypes.geometryColumn",                                               "geometry"),
                    RelationalDesignStrings.CannotFindTypeMappingForColumn("dbo.AllDataTypes.hierarchyidColumn",                                            "hierarchyid"),
                    RelationalDesignStrings.CannotFindTypeMappingForColumn("dbo.AllDataTypes.sql_variantColumn",                                            "sql_variant"),
                    RelationalDesignStrings.UnableToScaffoldIndexMissingProperty("IX_UnscaffoldableIndex",                                                  "sql_variantColumn,hierarchyidColumn"),
                    SqlServerDesignStrings.DataTypeDoesNotAllowSqlServerIdentityStrategy("dbo.PropertyConfiguration.PropertyConfigurationID",               "tinyint"),
                    RelationalDesignStrings.CannotFindTypeMappingForColumn("dbo.TableWithUnmappablePrimaryKeyColumn.TableWithUnmappablePrimaryKeyColumnID", "hierarchyid"),
                    RelationalDesignStrings.PrimaryKeyErrorPropertyNotFound("dbo.TableWithUnmappablePrimaryKeyColumn",                                      "TableWithUnmappablePrimaryKeyColumnID"),
                    RelationalDesignStrings.UnableToGenerateEntityType("dbo.TableWithUnmappablePrimaryKeyColumn")
                }
            });
            AssertEqualFileContents(expectedFileSet, actualFileSet);
            AssertCompile(actualFileSet);
        }
Exemplo n.º 4
0
        protected virtual EntityTypeBuilder VisitIndexes([NotNull] EntityTypeBuilder builder, [NotNull] IList <IndexModel> indexes)
        {
            Check.NotNull(builder, nameof(builder));
            Check.NotNull(indexes, nameof(indexes));

            foreach (var index in indexes)
            {
                var indexBuilder = VisitIndex(builder, index);

                if (indexBuilder == null)
                {
                    Logger.LogWarning(RelationalDesignStrings.UnableToScaffoldIndex(index.Name));
                }
            }

            return(builder);
        }
Exemplo n.º 5
0
        public virtual IModel GetMetadataModel([NotNull] ReverseEngineeringConfiguration configuration)
        {
            Check.NotNull(configuration, nameof(configuration));

            var metadataModel = _factory.Create(
                configuration.ConnectionString, configuration.TableSelectionSet);

            if (metadataModel == null)
            {
                throw new InvalidOperationException(
                          RelationalDesignStrings.ProviderReturnedNullModel(
                              _factory.GetType().FullName,
                              configuration.ConnectionString));
            }

            return(metadataModel);
        }
Exemplo n.º 6
0
        public virtual void CheckOutputFiles(
            [NotNull] string outputPath,
            [NotNull] string dbContextClassName,
            [NotNull] IModel metadataModel)
        {
            Check.NotEmpty(outputPath, nameof(outputPath));
            Check.NotEmpty(dbContextClassName, nameof(dbContextClassName));
            Check.NotNull(metadataModel, nameof(metadataModel));

            var readOnlyFiles = CodeWriter.GetReadOnlyFilePaths(
                outputPath, dbContextClassName, metadataModel.GetEntityTypes());

            if (readOnlyFiles.Count > 0)
            {
                throw new InvalidOperationException(
                          RelationalDesignStrings.ReadOnlyFiles(
                              outputPath, string.Join(", ", readOnlyFiles)));
            }
        }
Exemplo n.º 7
0
        public void It_logs_warning_for_bad_foreign_key()
        {
            var parentTable = new TableModel
            {
                Name    = "Parent",
                Columns =
                {
                    IdColumn,
                    new ColumnModel {
                        Name = "NotPkId",DataType              = "long", PrimaryKeyOrdinal = null
                    }
                }
            };
            var childrenTable = new TableModel
            {
                Name    = "Children",
                Columns =
                {
                    IdColumn,
                    new ColumnModel {
                        Name = "ParentId",DataType               = "long"
                    }
                }
            };

            childrenTable.ForeignKeys.Add(new ForeignKeyModel
            {
                Table            = childrenTable,
                Columns          = { childrenTable.Columns[1] },
                PrincipalTable   = parentTable,
                PrincipalColumns = { parentTable.Columns[1] }
            });

            _factory.Create(new DatabaseModel {
                Tables = { parentTable, childrenTable }
            });

            Assert.Contains("Warning: " +
                            RelationalDesignStrings.ForeignKeyScaffoldErrorPrincipalKeyNotFound(
                                childrenTable.ForeignKeys[0].DisplayName, "NotPkId", "Parent"),
                            _logger.FullLog);
        }
        public virtual void AddReferenceFromName([NotNull] string name)
        {
            Check.NotEmpty(name, nameof(name));

            if (!_isInitialized)
            {
                InitializeReferences();
            }

#if DNX451 || DNXCORE50
            var libraryExporter = CallContextServiceLocator.Locator.ServiceProvider.GetRequiredService <ILibraryExporter>();
            var libraryExport   = libraryExporter.GetExport(name);
            if (libraryExport != null)
            {
                foreach (var metadataReference in libraryExport.MetadataReferences)
                {
                    var roslynReference = metadataReference as IRoslynMetadataReference;
                    if (roslynReference != null)
                    {
                        _references.Add(roslynReference.MetadataReference);
                        return;
                    }

                    var fileMetadataReference = metadataReference as IMetadataFileReference;
                    if (fileMetadataReference != null)
                    {
                        var metadata = AssemblyMetadata.CreateFromStream(File.OpenRead(fileMetadataReference.Path));
                        _references.Add(metadata.GetReference());
                        return;
                    }
                }
            }

            throw new InvalidOperationException(RelationalDesignStrings.UnableToCreateMetadataReference(name));
#else
            _references.Add(MetadataReference.CreateFromFile(Assembly.Load(name).Location));
#endif
        }
Exemplo n.º 9
0
        public void Unmappable_column_type(string dataType)
        {
            var info = new DatabaseModel
            {
                Tables =
                {
                    new TableModel
                    {
                        Name    = "E",
                        Columns ={ IdColumn               }
                    }
                }
            };

            info.Tables.First().Columns.Add(new ColumnModel
            {
                Table    = info.Tables.First(),
                Name     = "Coli",
                DataType = dataType
            });

            Assert.Single(_factory.Create(info).FindEntityType("E").GetProperties());
            Assert.Contains(RelationalDesignStrings.CannotFindTypeMappingForColumn("E.Coli", dataType), _logger.FullLog);
        }
Exemplo n.º 10
0
        protected virtual EntityTypeBuilder VisitTable([NotNull] ModelBuilder modelBuilder, [NotNull] TableModel table)
        {
            Check.NotNull(modelBuilder, nameof(modelBuilder));
            Check.NotNull(table, nameof(table));

            var entityTypeName = GetEntityTypeName(table);

            var builder = modelBuilder.Entity(entityTypeName);

            var dbSetName = GetDbSetName(table);

            builder.Metadata.Scaffolding().DbSetName = dbSetName;

            builder.ToTable(table.Name, table.SchemaName);

            VisitColumns(builder, table.Columns);

            var keyBuilder = VisitPrimaryKey(builder, table);

            if (keyBuilder == null)
            {
                var errorMessage = RelationalDesignStrings.UnableToGenerateEntityType(table.DisplayName);
                Logger.LogWarning(
                    RelationalDesignEventId.UnableToGenerateEntityTypeWarning,
                    () => errorMessage);

                var model = modelBuilder.Model;
                model.RemoveEntityType(entityTypeName);
                model.Scaffolding().EntityTypeErrors.Add(entityTypeName, errorMessage);
                return(null);
            }

            VisitIndexes(builder, table.Indexes);

            return(builder);
        }
        public virtual void CheckOutputFiles(
            [NotNull] string outputPath,
            [NotNull] string dbContextClassName,
            [NotNull] IModel metadataModel,
            bool overwriteFiles)
        {
            Check.NotEmpty(outputPath, nameof(outputPath));
            Check.NotEmpty(dbContextClassName, nameof(dbContextClassName));
            Check.NotNull(metadataModel, nameof(metadataModel));

            var readOnlyFiles = CodeWriter.GetReadOnlyFilePaths(
                outputPath, dbContextClassName, metadataModel.GetEntityTypes());

            if (readOnlyFiles.Count > 0)
            {
                throw new InvalidOperationException(
                          RelationalDesignStrings.ReadOnlyFiles(
                              outputPath,
                              string.Join(
                                  CultureInfo.CurrentCulture.TextInfo.ListSeparator, readOnlyFiles)));
            }

            if (!overwriteFiles)
            {
                var existingFiles = CodeWriter.GetExistingFilePaths(
                    outputPath, dbContextClassName, metadataModel.GetEntityTypes());
                if (existingFiles.Count > 0)
                {
                    throw new InvalidOperationException(
                              RelationalDesignStrings.ExistingFiles(
                                  outputPath,
                                  string.Join(
                                      CultureInfo.CurrentCulture.TextInfo.ListSeparator, existingFiles)));
                }
            }
        }
Exemplo n.º 12
0
        public void Sequences()
        {
            using (var scratch = SqlServerTestStore.Create("SqlServerE2E"))
            {
                scratch.ExecuteNonQuery(@"
CREATE SEQUENCE CountByTwo
    START WITH 1
    INCREMENT BY 2;

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

CREATE SEQUENCE TinyIntSequence
    AS tinyint
    START WITH 1;

CREATE SEQUENCE SmallIntSequence
    AS smallint
    START WITH 1;

CREATE SEQUENCE IntSequence
    AS int
    START WITH 1;

CREATE SEQUENCE DecimalSequence
    AS decimal;

CREATE SEQUENCE NumericSequence
    AS numeric;");

                var configuration = new ReverseEngineeringConfiguration
                {
                    ConnectionString     = scratch.ConnectionString,
                    ProjectPath          = TestProjectDir + Path.DirectorySeparatorChar,
                    ProjectRootNamespace = TestNamespace,
                    ContextClassName     = "SequenceContext"
                };
                var expectedFileSet = new FileSet(new FileSystemFileService(),
                                                  Path.Combine("ReverseEngineering", "Expected"),
                                                  contents => contents.Replace("{{connectionString}}", scratch.ConnectionString))
                {
                    Files = new List <string> {
                        "SequenceContext.expected"
                    }
                };

                var filePaths = Generator.GenerateAsync(configuration).GetAwaiter().GetResult();

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

                AssertLog(new LoggerMessages
                {
                    Warn =
                    {
                        RelationalDesignStrings.BadSequenceType("DecimalSequence", "decimal"),
                        RelationalDesignStrings.BadSequenceType("NumericSequence", "numeric")
                    }
                });

                AssertEqualFileContents(expectedFileSet, actualFileSet);
                AssertCompile(actualFileSet);
            }
        }
Exemplo n.º 13
0
        protected virtual IMutableForeignKey VisitForeignKey([NotNull] ModelBuilder modelBuilder, [NotNull] ForeignKeyModel foreignKey)
        {
            Check.NotNull(modelBuilder, nameof(modelBuilder));
            Check.NotNull(foreignKey, nameof(foreignKey));

            if (foreignKey.PrincipalTable == null)
            {
                Logger.LogWarning(
                    RelationalDesignEventId.ForeignKeyReferencesMissingTableWarning,
                    () => RelationalDesignStrings.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 foreignKeyColumns        = foreignKey.Columns.OrderBy(fc => fc.Ordinal);
            var unmappedDependentColumns = foreignKeyColumns
                                           .Select(fc => fc.Column)
                                           .Where(c => _unmappedColumns.Contains(c))
                                           .Select(c => c.Name)
                                           .ToList();

            if (unmappedDependentColumns.Any())
            {
                Logger.LogWarning(
                    RelationalDesignEventId.ForeignKeyColumnsNotMappedWarning,
                    () => RelationalDesignStrings.ForeignKeyScaffoldErrorPropertyNotFound(
                        foreignKey.DisplayName,
                        string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator, unmappedDependentColumns)));
                return(null);
            }

            var dependentProperties = foreignKeyColumns
                                      .Select(fc => GetPropertyName(fc.Column))
                                      .Select(name => dependentEntityType.FindProperty(name))
                                      .ToList()
                                      .AsReadOnly();

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

            if (principalEntityType == null)
            {
                Logger.LogWarning(
                    RelationalDesignEventId.ForeignKeyReferencesMissingTableWarning,
                    () => RelationalDesignStrings.ForeignKeyScaffoldErrorPrincipalTableScaffoldingError(
                        foreignKey.DisplayName, foreignKey.PrincipalTable.DisplayName));
                return(null);
            }

            var unmappedPrincipalColumns = foreignKeyColumns
                                           .Select(fc => fc.PrincipalColumn)
                                           .Where(pc => principalEntityType.FindProperty(GetPropertyName(pc)) == null)
                                           .Select(pc => pc.Name)
                                           .ToList();

            if (unmappedPrincipalColumns.Any())
            {
                Logger.LogWarning(
                    RelationalDesignEventId.ForeignKeyColumnsNotMappedWarning,
                    () => RelationalDesignStrings.ForeignKeyScaffoldErrorPropertyNotFound(
                        foreignKey.DisplayName,
                        string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator, unmappedPrincipalColumns)));
                return(null);
            }

            var principalProperties = foreignKeyColumns
                                      .Select(fc => GetPropertyName(fc.PrincipalColumn))
                                      .Select(name => principalEntityType.FindProperty(name))
                                      .ToList()
                                      .AsReadOnly();

            var principalKey = principalEntityType.FindKey(principalProperties);

            if (principalKey == null)
            {
                var index = principalEntityType.FindIndex(principalProperties);
                if (index != null &&
                    index.IsUnique)
                {
                    principalKey = principalEntityType.AddKey(principalProperties);
                }
                else
                {
                    var principalColumns = foreignKeyColumns
                                           .Select(c => c.PrincipalColumn.Name)
                                           .Aggregate((a, b) => a + "," + b);

                    Logger.LogWarning(
                        RelationalDesignEventId.ForeignKeyReferencesMissingPrincipalKeyWarning,
                        () => RelationalDesignStrings.ForeignKeyScaffoldErrorPrincipalKeyNotFound(
                            foreignKey.DisplayName, principalColumns, principalEntityType.DisplayName()));
                    return(null);
                }
            }

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

            key.IsUnique = dependentEntityType.FindKey(dependentProperties) != null;

            key.Relational().Name = foreignKey.Name;

            AssignOnDeleteAction(foreignKey, key);

            return(key);
        }
Exemplo n.º 14
0
        protected virtual IndexBuilder VisitIndex([NotNull] EntityTypeBuilder builder, [NotNull] IndexModel index)
        {
            Check.NotNull(builder, nameof(builder));
            Check.NotNull(index, nameof(index));

            var indexColumns = index.IndexColumns
                               .OrderBy(ic => ic.Ordinal)
                               .Select(ic => ic.Column).ToList();
            var unmappedColumns = indexColumns
                                  .Where(c => _unmappedColumns.Contains(c))
                                  .Select(c => c.Name).ToList();

            if (unmappedColumns.Any())
            {
                Logger.LogWarning(
                    RelationalDesignEventId.IndexColumnsNotMappedWarning,
                    () => RelationalDesignStrings.UnableToScaffoldIndexMissingProperty(
                        index.Name,
                        string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator, unmappedColumns)));
                return(null);
            }

            var columnNames   = indexColumns.Select(c => c.Name);
            var propertyNames = indexColumns.Select(GetPropertyName).ToArray();

            if (index.Table != null)
            {
                var primaryKeyColumns = index.Table.Columns
                                        .Where(c => c.PrimaryKeyOrdinal.HasValue)
                                        .OrderBy(c => c.PrimaryKeyOrdinal);
                if (columnNames.SequenceEqual(primaryKeyColumns.Select(c => c.Name)) && index.Filter == null)
                {
                    // index is supporting the primary key. So there is no need for
                    // an extra index in the model. But if the index name does not
                    // match what would be produced by default then need to call
                    // HasName() on the primary key.
                    if (index.Name !=
                        RelationalKeyAnnotations
                        .GetDefaultKeyName(
                            index.Table.Name,
                            true,     /* is primary key */
                            primaryKeyColumns.Select(GetPropertyName)))
                    {
                        builder.HasKey(propertyNames).HasName(index.Name);
                    }
                    return(null);
                }
            }

            var indexBuilder = builder.HasIndex(propertyNames)
                               .IsUnique(index.IsUnique);

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

            if (!string.IsNullOrEmpty(index.Name))
            {
                indexBuilder.HasName(index.Name);
            }

            if (index.IsUnique)
            {
                var keyBuilder = builder.HasAlternateKey(propertyNames);
                if (!string.IsNullOrEmpty(index.Name))
                {
                    keyBuilder.HasName(index.Name);
                }
            }

            return(indexBuilder);
        }
Exemplo n.º 15
0
        protected virtual PropertyBuilder VisitColumn([NotNull] EntityTypeBuilder builder, [NotNull] ColumnModel column)
        {
            Check.NotNull(builder, nameof(builder));
            Check.NotNull(column, nameof(column));

            var typeMapping = GetTypeMapping(column);

            var clrType = typeMapping?.ClrType;

            if (clrType == null)
            {
                _unmappedColumns.Add(column);
                Logger.LogWarning(
                    RelationalDesignEventId.ColumnTypeNotMappedWarning,
                    () => RelationalDesignStrings.CannotFindTypeMappingForColumn(column.DisplayName, column.DataType));
                return(null);
            }

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

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

            if (TypeMapper.GetMapping(property.Metadata).StoreType != column.DataType &&
                !string.IsNullOrWhiteSpace(column.DataType))
            {
                property.HasColumnType(column.DataType);
            }

            property.HasColumnName(column.Name);

            if (column.MaxLength.HasValue)
            {
                property.HasMaxLength(column.MaxLength.Value);
            }

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

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

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

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

            if (!column.PrimaryKeyOrdinal.HasValue)
            {
                property.IsRequired(!column.IsNullable);
            }

            property.Metadata.Scaffolding().ColumnOrdinal = column.Ordinal;
            return(property);
        }
Exemplo n.º 16
0
        protected virtual IndexBuilder VisitIndex([NotNull] EntityTypeBuilder builder, [NotNull] IndexModel index)
        {
            Check.NotNull(builder, nameof(builder));
            Check.NotNull(index, nameof(index));

            var propertyNames = index.IndexColumns
                                .OrderBy(ic => ic.Ordinal)
                                .Select(ic => GetPropertyName(ic.Column))
                                .ToArray();

            if (propertyNames.Count(p => builder.Metadata.FindProperty(p) != null) != propertyNames.Length)
            {
                Logger.LogWarning(RelationalDesignStrings.UnableToScaffoldIndexMissingProperty(index.Name));
                return(null);
            }

            var columnNames = index.IndexColumns
                              .OrderBy(ic => ic.Ordinal)
                              .Select(ic => ic.Column.Name);

            if (index.Table != null)
            {
                var primaryKeyColumns = index.Table.Columns
                                        .Where(c => c.PrimaryKeyOrdinal.HasValue)
                                        .OrderBy(c => c.PrimaryKeyOrdinal);
                if (columnNames.SequenceEqual(primaryKeyColumns.Select(c => c.Name)))
                {
                    // index is supporting the primary key. So there is no need for
                    // an extra index in the model. But if the index name does not
                    // match what would be produced by default then need to call
                    // HasName() on the primary key.
                    if (index.Name !=
                        RelationalKeyAnnotations
                        .GetDefaultKeyName(
                            index.Table.Name,
                            true,     /* is primary key */
                            primaryKeyColumns.Select(c => GetPropertyName(c))))
                    {
                        builder.HasKey(propertyNames.ToArray()).HasName(index.Name);
                    }
                    return(null);
                }
            }

            var indexBuilder = builder.HasIndex(propertyNames)
                               .IsUnique(index.IsUnique);

            if (!string.IsNullOrEmpty(index.Name))
            {
                indexBuilder.HasName(index.Name);
            }

            if (index.IsUnique)
            {
                var keyBuilder = builder.HasAlternateKey(propertyNames);
                if (!string.IsNullOrEmpty(index.Name))
                {
                    keyBuilder.HasName(index.Name);
                }
            }

            return(indexBuilder);
        }
Exemplo n.º 17
0
        protected virtual IMutableForeignKey VisitForeignKey([NotNull] ModelBuilder modelBuilder, [NotNull] ForeignKeyModel foreignKey)
        {
            Check.NotNull(modelBuilder, nameof(modelBuilder));
            Check.NotNull(foreignKey, nameof(foreignKey));

            if (foreignKey.PrincipalTable == null)
            {
                Logger.LogWarning(
                    RelationalDesignEventId.ForeignKeyReferencesMissingTableWarning,
                    () => RelationalDesignStrings.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 foreignKeyColumns        = foreignKey.Columns.OrderBy(fc => fc.Ordinal);
            var unmappedDependentColumns = foreignKeyColumns
                                           .Select(fc => fc.Column)
                                           .Where(c => _unmappedColumns.Contains(c))
                                           .Select(c => c.Name)
                                           .ToList();

            if (unmappedDependentColumns.Any())
            {
                Logger.LogWarning(
                    RelationalDesignEventId.ForeignKeyColumnsNotMappedWarning,
                    () => RelationalDesignStrings.ForeignKeyScaffoldErrorPropertyNotFound(
                        foreignKey.DisplayName,
                        string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator, unmappedDependentColumns)));
                return(null);
            }

            var dependentProperties = foreignKeyColumns
                                      .Select(fc => GetPropertyName(fc.Column))
                                      .Select(name => dependentEntityType.FindProperty(name))
                                      .ToList()
                                      .AsReadOnly();

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

            if (principalEntityType == null)
            {
                Logger.LogWarning(
                    RelationalDesignEventId.ForeignKeyReferencesMissingTableWarning,
                    () => RelationalDesignStrings.ForeignKeyScaffoldErrorPrincipalTableScaffoldingError(
                        foreignKey.DisplayName, foreignKey.PrincipalTable.DisplayName));
                return(null);
            }

            var unmappedPrincipalColumns = foreignKeyColumns
                                           .Select(fc => fc.PrincipalColumn)
                                           .Where(pc => principalEntityType.FindProperty(GetPropertyName(pc)) == null)
                                           .Select(pc => pc.Name)
                                           .ToList();

            if (unmappedPrincipalColumns.Any())
            {
                Logger.LogWarning(
                    RelationalDesignEventId.ForeignKeyColumnsNotMappedWarning,
                    () => RelationalDesignStrings.ForeignKeyScaffoldErrorPropertyNotFound(
                        foreignKey.DisplayName,
                        string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator, unmappedPrincipalColumns)));
                return(null);
            }

            var principalPropertiesMap = foreignKeyColumns
                                         .Select(fc => new Tuple <IMutableProperty, ColumnModel>(
                                                     principalEntityType.FindProperty(GetPropertyName(fc.PrincipalColumn)),
                                                     fc.PrincipalColumn));
            var principalProperties = principalPropertiesMap
                                      .Select(tuple => tuple.Item1).ToList();

            var principalKey = principalEntityType.FindKey(principalProperties);

            if (principalKey == null)
            {
                var index = principalEntityType.FindIndex(principalProperties.AsReadOnly());
                if (index != null &&
                    index.IsUnique)
                {
                    // 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.Item1.IsNullable);
                    if (nullablePrincipalProperties.Any())
                    {
                        Logger.LogWarning(
                            RelationalDesignEventId.ForeignKeyPrincipalEndContainsNullableColumns,
                            () => RelationalDesignStrings.ForeignKeyPrincipalEndContainsNullableColumns(
                                foreignKey.DisplayName,
                                index.Relational().Name,
                                nullablePrincipalProperties
                                .Select(tuple => tuple.Item2.DisplayName)
                                .Aggregate((a, b) => a + "," + b)));
                        nullablePrincipalProperties
                        .ToList().ForEach(tuple => tuple.Item1.IsNullable = false);
                    }
                    principalKey = principalEntityType.AddKey(principalProperties);
                }
                else
                {
                    var principalColumns = foreignKeyColumns
                                           .Select(c => c.PrincipalColumn.Name)
                                           .Aggregate((a, b) => a + "," + b);

                    Logger.LogWarning(
                        RelationalDesignEventId.ForeignKeyReferencesMissingPrincipalKeyWarning,
                        () => RelationalDesignStrings.ForeignKeyScaffoldErrorPrincipalKeyNotFound(
                            foreignKey.DisplayName, 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 != null && dependentIndex.IsUnique);

            key.Relational().Name = foreignKey.Name;

            AssignOnDeleteAction(foreignKey, key);

            return(key);
        }
Exemplo n.º 18
0
        protected virtual IMutableForeignKey VisitForeignKey([NotNull] ModelBuilder modelBuilder, [NotNull] ForeignKeyModel foreignKey)
        {
            Check.NotNull(modelBuilder, nameof(modelBuilder));
            Check.NotNull(foreignKey, nameof(foreignKey));

            if (foreignKey.PrincipalTable == null)
            {
                Logger.LogWarning(RelationalDesignStrings.ForeignKeyScaffoldErrorPrincipalTableNotFound(foreignKey.DisplayName));
                return(null);
            }

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

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

            var depProps = foreignKey.Columns
                           .Select(GetPropertyName)
                           .Select(@from => dependentEntityType.FindProperty(@from))
                           .ToList()
                           .AsReadOnly();

            if (depProps.Any(p => p == null))
            {
                // TODO log which column was not found
                Logger.LogWarning(RelationalDesignStrings.ForeignKeyScaffoldErrorPropertyNotFound(foreignKey.DisplayName));
                return(null);
            }

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

            if (principalEntityType == null)
            {
                Logger.LogWarning(RelationalDesignStrings.ForeignKeyScaffoldErrorPrincipalTableScaffoldingError(foreignKey.DisplayName, foreignKey.PrincipalTable.DisplayName));
                return(null);
            }

            var principalProps = foreignKey.PrincipalColumns
                                 .Select(GetPropertyName)
                                 .Select(to => principalEntityType.FindProperty(to))
                                 .ToList()
                                 .AsReadOnly();

            if (principalProps.Any(p => p == null))
            {
                Logger.LogWarning(RelationalDesignStrings.ForeignKeyScaffoldErrorPropertyNotFound(foreignKey.DisplayName));
                return(null);
            }

            var principalKey = principalEntityType.FindKey(principalProps);

            if (principalKey == null)
            {
                var index = principalEntityType.FindIndex(principalProps);
                if (index != null &&
                    index.IsUnique == true)
                {
                    principalKey = principalEntityType.AddKey(principalProps);
                }
                else
                {
                    var principalColumns = foreignKey.PrincipalColumns.Select(c => c.Name).Aggregate((a, b) => a + "," + b);
                    Logger.LogWarning(
                        RelationalDesignStrings.ForeignKeyScaffoldErrorPrincipalKeyNotFound(
                            foreignKey.DisplayName, principalColumns, principalEntityType.DisplayName()));
                    return(null);
                }
            }

            var key = dependentEntityType.GetOrAddForeignKey(depProps, principalKey, principalEntityType);

            key.IsUnique = dependentEntityType.FindKey(depProps) != null;

            AssignOnDeleteAction(foreignKey, key);

            return(key);
        }
Exemplo n.º 19
0
        public virtual void AddNavigationProperties([NotNull] EntityConfiguration entityConfiguration)
        {
            Check.NotNull(entityConfiguration, nameof(entityConfiguration));

            foreach (var otherEntityType in entityConfiguration.EntityType
                     .Model.EntityTypes.Where(et => et != entityConfiguration.EntityType))
            {
                // set up the navigation properties for foreign keys from another EntityType
                // which reference this EntityType (i.e. this EntityType is the principal)
                foreach (var foreignKey in otherEntityType
                         .GetForeignKeys().Where(fk => fk.PrincipalEntityType == entityConfiguration.EntityType))
                {
                    if (((EntityType)otherEntityType)
                        .FindAnnotation(RelationalMetadataModelProvider.AnnotationNameEntityTypeError) != null)
                    {
                        entityConfiguration.NavigationPropertyConfigurations.Add(
                            new NavigationPropertyConfiguration(
                                RelationalDesignStrings.UnableToAddNavigationProperty(otherEntityType.Name)));
                    }
                    else
                    {
                        var referencedType = foreignKey.IsUnique
                            ? otherEntityType.Name
                            : "ICollection<" + otherEntityType.Name + ">";
                        var navPropConfiguration =
                            new NavigationPropertyConfiguration(
                                referencedType,
                                (string)foreignKey[RelationalMetadataModelProvider.AnnotationNamePrincipalEndNavPropName]);

                        if (foreignKey.PrincipalKey.IsPrimaryKey())
                        {
                            navPropConfiguration.AttributeConfigurations.Add(
                                new AttributeConfiguration(
                                    nameof(InversePropertyAttribute),
                                    CSharpUtilities.DelimitString(
                                        (string)foreignKey[RelationalMetadataModelProvider.AnnotationNameDependentEndNavPropName])));
                        }

                        entityConfiguration.NavigationPropertyConfigurations.Add(
                            navPropConfiguration);
                    }
                }
            }

            foreach (var foreignKey in entityConfiguration.EntityType.GetForeignKeys())
            {
                // set up the navigation property on this end of foreign keys owned by this EntityType
                // (i.e. this EntityType is the dependent)
                var dependentEndNavPropConfiguration =
                    new NavigationPropertyConfiguration(
                        foreignKey.PrincipalEntityType.Name,
                        (string)foreignKey[RelationalMetadataModelProvider.AnnotationNameDependentEndNavPropName]);

                if (foreignKey.PrincipalKey.IsPrimaryKey())
                {
                    dependentEndNavPropConfiguration.AttributeConfigurations.Add(
                        new AttributeConfiguration(
                            nameof(ForeignKeyAttribute),
                            CSharpUtilities.DelimitString(
                                string.Join(",", foreignKey.Properties.Select(p => p.Name)))));
                    dependentEndNavPropConfiguration.AttributeConfigurations.Add(
                        new AttributeConfiguration(
                            nameof(InversePropertyAttribute),
                            CSharpUtilities.DelimitString(
                                (string)foreignKey[RelationalMetadataModelProvider.AnnotationNamePrincipalEndNavPropName])));
                }

                entityConfiguration.NavigationPropertyConfigurations.Add(
                    dependentEndNavPropConfiguration);

                // set up the other navigation property for self-referencing foreign keys owned by this EntityType
                if (((ForeignKey)foreignKey).IsSelfReferencing())
                {
                    var referencedType = foreignKey.IsUnique
                        ? foreignKey.DeclaringEntityType.Name
                        : "ICollection<" + foreignKey.DeclaringEntityType.Name + ">";
                    var principalEndNavPropConfiguration = new NavigationPropertyConfiguration(
                        referencedType,
                        (string)foreignKey[RelationalMetadataModelProvider.AnnotationNamePrincipalEndNavPropName]);
                    principalEndNavPropConfiguration.AttributeConfigurations.Add(
                        new AttributeConfiguration(
                            nameof(InversePropertyAttribute),
                            CSharpUtilities.DelimitString(
                                (string)foreignKey[RelationalMetadataModelProvider.AnnotationNameDependentEndNavPropName])));
                    entityConfiguration.NavigationPropertyConfigurations.Add(
                        principalEndNavPropConfiguration);
                }
            }
        }