Skip to content

Commit

Permalink
Further merge query types into entity types
Browse files Browse the repository at this point in the history
Changes:
- Un-obsolete ToView
- Differentiate between views and keyless tables in RevEng
- Ignore ToView and ToQuery in Migrations; handle HasNoKey
- Handle duplicate table names when HasNoKey
  • Loading branch information
bricelam committed Aug 13, 2019
1 parent 7f7b712 commit 8bfd1da
Show file tree
Hide file tree
Showing 36 changed files with 460 additions and 118 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public virtual void Generate(string builderName, IModel model, IndentedStringBui
stringBuilder.AppendLine(";");
}

GenerateEntityTypes(builderName, Sort(model.GetEntityTypes().Where(et => et.FindPrimaryKey() != null).ToList()), stringBuilder);
GenerateEntityTypes(builderName, Sort(model.GetEntityTypes().Where(et => !et.MigrationsIgnored()).ToList()), stringBuilder);
}

private static IReadOnlyList<IEntityType> Sort(IReadOnlyList<IEntityType> entityTypes)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,10 @@ private void GenerateEntityType(IEntityType entityType, bool useDataAnnotations)
RemoveAnnotation(ref annotations, RelationalAnnotationNames.Comment);
RemoveAnnotation(ref annotations, RelationalAnnotationNames.Schema);
RemoveAnnotation(ref annotations, ScaffoldingAnnotationNames.DbSetName);
RemoveAnnotation(ref annotations, RelationalAnnotationNames.ViewDefinition);

if (!useDataAnnotations)
var isView = entityType.FindAnnotation(RelationalAnnotationNames.ViewDefinition) != null;
if (!useDataAnnotations || isView)
{
GenerateTableName(entityType);
}
Expand Down Expand Up @@ -526,7 +528,8 @@ private void GenerateTableName(IEntityType entityType)
var explicitSchema = schema != null && schema != defaultSchema;
var explicitTable = explicitSchema || tableName != null && tableName != entityType.GetDbSetName();

if (explicitTable)
var isView = entityType.FindAnnotation(RelationalAnnotationNames.ViewDefinition) != null;
if (explicitTable || isView)
{
var parameterString = _code.Literal(tableName);
if (explicitSchema)
Expand All @@ -536,7 +539,7 @@ private void GenerateTableName(IEntityType entityType)

var lines = new List<string>
{
$".{nameof(RelationalEntityTypeBuilderExtensions.ToTable)}({parameterString})"
$".{(isView ? nameof(RelationalEntityTypeBuilderExtensions.ToView) : nameof(RelationalEntityTypeBuilderExtensions.ToTable))}({parameterString})"
};

AppendMultiLineFluentApi(entityType, lines);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ private void GenerateTableAttribute(IEntityType entityType)
var defaultSchema = entityType.Model.GetDefaultSchema();

var schemaParameterNeeded = schema != null && schema != defaultSchema;
var tableAttributeNeeded = schemaParameterNeeded || tableName != null && tableName != entityType.GetDbSetName();
var isView = entityType.FindAnnotation(RelationalAnnotationNames.ViewDefinition) != null;
var tableAttributeNeeded = !isView && (schemaParameterNeeded || tableName != null && tableName != entityType.GetDbSetName());

if (tableAttributeNeeded)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,14 @@ protected virtual EntityTypeBuilder VisitTable([NotNull] ModelBuilder modelBuild
var dbSetName = GetDbSetName(table);
builder.Metadata.SetDbSetName(dbSetName);

builder.ToTable(table.Name, table.Schema);
if (table is DatabaseView)
{
builder.ToView(table.Name, table.Schema);
}
else
{
builder.ToTable(table.Name, table.Schema);
}

if (table.Comment != null)
{
Expand Down

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -277,5 +277,22 @@ public static void SetComment(
[NotNull] this IConventionEntityType entityType, [CanBeNull] string comment, bool fromDataAnnotation = false)
=> entityType.SetOrRemoveAnnotation(RelationalAnnotationNames.Comment, comment, fromDataAnnotation);

/// <summary>
/// Gets a value indicating whether the entity type is ignored by Migrations.
/// </summary>
/// <param name="entityType">The entity type.</param>
/// <returns>A value indicating whether the entity type is ignored by Migrations.</returns>
public static bool MigrationsIgnored([NotNull] this IEntityType entityType)
{
if (entityType.BaseType != null)
{
return entityType.BaseType.MigrationsIgnored();
}

var viewDefinition = entityType.FindAnnotation(RelationalAnnotationNames.ViewDefinition);

return (viewDefinition != null && viewDefinition.Value == null)
|| entityType.GetDefiningQuery() != null;
}
}
}
18 changes: 9 additions & 9 deletions src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ protected virtual void ValidateDbFunctions([NotNull] IModel model, [NotNull] IDi

foreach (var parameter in dbFunction.Parameters)
{
if(parameter.TypeMapping == null)
if (parameter.TypeMapping == null)
{
throw new InvalidOperationException(
RelationalStrings.DbFunctionInvalidParameterType(
Expand Down Expand Up @@ -152,7 +152,7 @@ protected virtual void ValidateSharedTableCompatibility(
[NotNull] IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
{
var tables = new Dictionary<string, List<IEntityType>>();
foreach (var entityType in model.GetEntityTypes().Where(et => et.FindPrimaryKey() != null))
foreach (var entityType in model.GetEntityTypes())
{
var tableName = Format(entityType.GetSchema(), entityType.GetTableName());

Expand Down Expand Up @@ -196,11 +196,11 @@ protected virtual void ValidateSharedTableCompatibility(
foreach (var mappedType in mappedTypes)
{
if (mappedType.BaseType != null
|| mappedType.FindForeignKeys(mappedType.FindPrimaryKey().Properties)
|| (mappedType.FindPrimaryKey() != null && mappedType.FindForeignKeys(mappedType.FindPrimaryKey().Properties)
.Any(
fk => fk.PrincipalKey.IsPrimaryKey()
&& fk.PrincipalEntityType.RootType() != mappedType
&& unvalidatedTypes.Contains(fk.PrincipalEntityType)))
&& unvalidatedTypes.Contains(fk.PrincipalEntityType))))
{
continue;
}
Expand Down Expand Up @@ -235,17 +235,17 @@ protected virtual void ValidateSharedTableCompatibility(
{
var key = entityType.FindPrimaryKey();
var otherKey = nextEntityType.FindPrimaryKey();
if (key.GetName() != otherKey.GetName())
if (key?.GetName() != otherKey?.GetName())
{
throw new InvalidOperationException(
RelationalStrings.IncompatibleTableKeyNameMismatch(
tableName,
entityType.DisplayName(),
nextEntityType.DisplayName(),
key.GetName(),
key.Properties.Format(),
otherKey.GetName(),
otherKey.Properties.Format()));
key?.GetName(),
key?.Properties.Format(),
otherKey?.GetName(),
otherKey?.Properties.Format()));
}

var nextComment = nextEntityType.GetComment();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,6 @@ private static void TryUniquifyTableNames(
{
foreach (var entityType in model.GetEntityTypes())
{
if (entityType.FindPrimaryKey() == null)
{
continue;
}

var tableName = (Schema: entityType.GetSchema(), TableName: entityType.GetTableName());
if (!tables.TryGetValue(tableName, out var entityTypes))
{
Expand Down Expand Up @@ -131,8 +126,8 @@ private static void TryUniquifyTableNames(
private static bool ShouldUniquify(IConventionEntityType entityType, ICollection<IConventionEntityType> entityTypes)
{
var rootType = entityType.RootType();
var pkProperty = entityType.FindPrimaryKey().Properties[0];
var rootSharedTableType = pkProperty.FindSharedTableRootPrimaryKeyProperty()?.DeclaringEntityType;
var pkProperty = entityType.FindPrimaryKey()?.Properties[0];
var rootSharedTableType = pkProperty?.FindSharedTableRootPrimaryKeyProperty()?.DeclaringEntityType;

foreach (var otherEntityType in entityTypes)
{
Expand All @@ -142,8 +137,8 @@ private static bool ShouldUniquify(IConventionEntityType entityType, ICollection
return false;
}

var otherPkProperty = otherEntityType.FindPrimaryKey().Properties[0];
var otherRootSharedTableType = otherPkProperty.FindSharedTableRootPrimaryKeyProperty()?.DeclaringEntityType;
var otherPkProperty = otherEntityType.FindPrimaryKey()?.Properties[0];
var otherRootSharedTableType = otherPkProperty?.FindSharedTableRootPrimaryKeyProperty()?.DeclaringEntityType;
if (otherRootSharedTableType == entityType
|| (otherRootSharedTableType == rootSharedTableType
&& otherRootSharedTableType != null))
Expand Down
6 changes: 3 additions & 3 deletions src/EFCore.Relational/Metadata/Internal/TableMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,12 @@ public TableMapping(
public virtual IEntityType GetRootType()
=> EntityTypes.SingleOrDefault(
t => t.BaseType == null
&& t.FindForeignKeys(t.FindDeclaredPrimaryKey().Properties)
&& (t.FindDeclaredPrimaryKey() == null || t.FindForeignKeys(t.FindDeclaredPrimaryKey().Properties)
.All(
fk => !fk.PrincipalKey.IsPrimaryKey()
|| fk.PrincipalEntityType.RootType() == t
|| t.GetTableName() != fk.PrincipalEntityType.GetTableName()
|| t.GetSchema() != fk.PrincipalEntityType.GetSchema()));
|| t.GetSchema() != fk.PrincipalEntityType.GetSchema())));

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down Expand Up @@ -155,7 +155,7 @@ public virtual IEnumerable<ICheckConstraint> GetCheckConstraints()
public static IReadOnlyList<TableMapping> GetTableMappings([NotNull] IModel model)
{
var tables = new Dictionary<(string Schema, string TableName), List<IEntityType>>();
foreach (var entityType in model.GetEntityTypes().Where(et => et.FindPrimaryKey() != null))
foreach (var entityType in model.GetEntityTypes().Where(et => !et.MigrationsIgnored()))
{
var fullName = (entityType.GetSchema(), entityType.GetTableName());
if (!tables.TryGetValue(fullName, out var mappedEntityTypes))
Expand Down
5 changes: 5 additions & 0 deletions src/EFCore.Relational/Metadata/RelationalAnnotationNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,10 @@ public static class RelationalAnnotationNames
/// A flag indicating whether the property is constrained to fixed length values.
/// </summary>
public const string IsFixedLength = Prefix + "IsFixedLength";

/// <summary>
/// The definition of a database view.
/// </summary>
public const string ViewDefinition = Prefix + "ViewDefinition";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,10 @@ protected virtual IEnumerable<MigrationOperation> Add(
createTableOperation.Columns.AddRange(
GetSortedProperties(target).SelectMany(p => Add(p, diffContext, inline: true)).Cast<AddColumnOperation>());
var primaryKey = target.EntityTypes[0].FindPrimaryKey();
createTableOperation.PrimaryKey = Add(primaryKey, diffContext).Cast<AddPrimaryKeyOperation>().Single();
if (primaryKey != null)
{
createTableOperation.PrimaryKey = Add(primaryKey, diffContext).Cast<AddPrimaryKeyOperation>().Single();
}
createTableOperation.UniqueConstraints.AddRange(
target.GetKeys().Where(k => !k.IsPrimaryKey()).SelectMany(k => Add(k, diffContext))
.Cast<AddUniqueConstraintOperation>());
Expand Down Expand Up @@ -2147,7 +2150,7 @@ protected virtual bool HasDifferences([NotNull] IEnumerable<IAnnotation> source,
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
protected virtual IEnumerable<string> GetSchemas([NotNull] IModel model)
=> model.GetRootEntityTypes().Select(t => t.GetSchema())
=> model.GetRootEntityTypes().Where(t => !t.MigrationsIgnored()).Select(t => t.GetSchema())
.Concat(model.GetSequences().Select(s => s.Schema))
.Where(s => !string.IsNullOrEmpty(s))
.Distinct();
Expand Down
3 changes: 1 addition & 2 deletions src/EFCore.Relational/Migrations/MigrationsSqlGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Migrations.Operations;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Update;
Expand Down Expand Up @@ -1580,7 +1579,7 @@ protected virtual IEnumerable<IEntityType> FindEntityTypes(
[CanBeNull] string schema,
[NotNull] string tableName)
=> model?.GetEntityTypes().Where(
t => t.GetTableName() == tableName && t.GetSchema() == schema && t.FindPrimaryKey() != null);
t => t.GetTableName() == tableName && t.GetSchema() == schema && !t.MigrationsIgnored());

/// <summary>
/// <para>
Expand Down
12 changes: 12 additions & 0 deletions src/EFCore.Relational/Scaffolding/Metadata/DatabaseView.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

namespace Microsoft.EntityFrameworkCore.Scaffolding.Metadata
{
/// <summary>
/// A simple model for a database view used when reverse engineering an existing database.
/// </summary>
public class DatabaseView : DatabaseTable
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public static SharedTableEntryMapFactory<TValue> CreateSharedTableEntryMapFactor
{
var principals = new Dictionary<IEntityType, IReadOnlyList<IEntityType>>(entityTypes.Count);
var dependents = new Dictionary<IEntityType, IReadOnlyList<IEntityType>>(entityTypes.Count);
foreach (var entityType in entityTypes)
foreach (var entityType in entityTypes.Where(t => t.FindPrimaryKey() != null))
{
var principalList = new List<IEntityType>();
foreach (var foreignKey in entityType.FindForeignKeys(entityType.FindPrimaryKey().Properties))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,8 @@ private IEnumerable<DatabaseTable> GetTables(
SELECT
SCHEMA_NAME([t].[schema_id]) AS [schema],
[t].[name],
CAST([e].[value] AS nvarchar(MAX)) AS [comment]";
CAST([e].[value] AS nvarchar(MAX)) AS [comment],
'table' AS [type]";

if (supportsMemoryOptimizedTable)
{
Expand Down Expand Up @@ -487,7 +488,8 @@ FROM [sys].[extended_properties] AS [ep]
SELECT
SCHEMA_NAME([v].[schema_id]) AS [schema],
[v].[name],
CAST([e].[value] AS nvarchar(MAX)) AS [comment]";
CAST([e].[value] AS nvarchar(MAX)) AS [comment],
'view' AS [type]";

if (supportsMemoryOptimizedTable)
{
Expand Down Expand Up @@ -520,15 +522,17 @@ FROM [sys].[views] AS [v]
var schema = reader.GetValueOrDefault<string>("schema");
var name = reader.GetValueOrDefault<string>("name");
var comment = reader.GetValueOrDefault<string>("comment");
var type = reader.GetValueOrDefault<string>("type");

_logger.TableFound(DisplayName(schema, name));

var table = new DatabaseTable
{
Schema = schema,
Name = name,
Comment = comment,
};
var table = type == "table"
? new DatabaseTable()
: new DatabaseView();

table.Schema = schema;
table.Name = name;
table.Comment = comment;

if (supportsMemoryOptimizedTable)
{
Expand Down Expand Up @@ -832,7 +836,7 @@ FROM [sys].[indexes] i
)";
}

commandText += @"
commandText += @"
ORDER BY [table_schema], [table_name], [index_name], [ic].[key_ordinal]";

command.CommandText = commandText;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ private IEnumerable<DatabaseTable> GetTables(DbConnection connection, IEnumerabl
using (var command = connection.CreateCommand())
{
command.CommandText = new StringBuilder()
.AppendLine("SELECT \"name\"")
.AppendLine("SELECT \"name\", \"type\"")
.AppendLine("FROM \"sqlite_master\"")
.Append("WHERE \"type\" IN ('table', 'view') AND instr(\"name\", 'sqlite_') <> 1 AND \"name\" NOT IN ('")
.Append(HistoryRepository.DefaultTableName)
Expand All @@ -179,10 +179,12 @@ private IEnumerable<DatabaseTable> GetTables(DbConnection connection, IEnumerabl

_logger.TableFound(name);

var table = new DatabaseTable
{
Name = name
};
var type = reader.GetString(1);
var table = type == "table"
? new DatabaseTable()
: new DatabaseView();

table.Name = name;

foreach (var column in GetColumns(connection, name))
{
Expand Down
Loading

0 comments on commit 8bfd1da

Please sign in to comment.