Skip to content

Commit

Permalink
Consolidate EntityType and QueryType
Browse files Browse the repository at this point in the history
Mark QUery methods and types as obsolete
Throw when ToTable is called on derived types

Fixes #14194
Fixes #11811
  • Loading branch information
AndriySvyryd committed Feb 22, 2019
1 parent b7c17b1 commit 0830c10
Show file tree
Hide file tree
Showing 109 changed files with 837 additions and 1,907 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public InternalEntityTypeBuilder Apply(InternalEntityTypeBuilder entityTypeBuild
var entityType = entityTypeBuilder.Metadata;
if (entityType.BaseType == null
&& entityType.IsDocumentRoot()
&& !entityType.IsQueryType)
&& !entityType.IsKeyless)
{
var idProperty = entityTypeBuilder.Property(IdPropertyName, typeof(string), ConfigurationSource.Convention);
idProperty.HasValueGenerator((_, __) => new IdValueGenerator(), ConfigurationSource.Convention);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ protected override Expression VisitEntityQueryable([NotNull] Type elementType)
new EntityShaper(
entityType,
trackingQuery: QueryModelVisitor.QueryCompilationContext.IsTrackingQuery
&& !entityType.IsQueryType,
&& entityType.FindPrimaryKey() != null,
useQueryBuffer: QueryModelVisitor.QueryCompilationContext.IsQueryBufferRequired
&& !entityType.IsQueryType,
&& entityType.FindPrimaryKey() != null,
_entityMaterializerSource));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public virtual void Generate(string builderName, IModel model, IndentedStringBui
stringBuilder.AppendLine(";");
}

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

private static IReadOnlyList<IEntityType> Sort(IReadOnlyList<IEntityType> entityTypes)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ protected override Expression VisitEntityQueryable(Type elementType)
materializer,
Expression.Constant(
QueryModelVisitor.QueryCompilationContext.IsTrackingQuery
&& !entityType.IsQueryType));
&& entityType.FindPrimaryKey() != null));
}

return Expression.Call(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ protected virtual void ValidateDefaultValuesOnKeys([NotNull] IModel model, Diagn
protected virtual void ValidateSharedTableCompatibility([NotNull] IModel model, DiagnosticsLoggers loggers)
{
var tables = new Dictionary<string, List<IEntityType>>();
foreach (var entityType in model.GetEntityTypes().Where(et => !et.IsQueryType))
foreach (var entityType in model.GetEntityTypes().Where(et => et.FindPrimaryKey() != null))
{
var annotations = entityType.Relational();
var tableName = Format(annotations.Schema, annotations.TableName);
Expand Down Expand Up @@ -472,11 +472,12 @@ protected virtual void ValidateInheritanceMapping([NotNull] IModel model, Diagno
foreach (var entityType in model.GetEntityTypes())
{
if (entityType.BaseType != null
&& entityType.IsQueryType
&& entityType[RelationalAnnotationNames.TableName] != null)
&& entityType[RelationalAnnotationNames.TableName] != null
&& ((EntityType)entityType).FindAnnotation(RelationalAnnotationNames.TableName).GetConfigurationSource()
== ConfigurationSource.Explicit)
{
throw new InvalidOperationException(
RelationalStrings.DerivedQueryTypeView(entityType.DisplayName(), entityType.BaseType.DisplayName()));
RelationalStrings.DerivedTypeTable(entityType.DisplayName(), entityType.BaseType.DisplayName()));
}
}
}
Expand Down
12 changes: 2 additions & 10 deletions src/EFCore.Relational/Metadata/Builders/DiscriminatorBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,7 @@ public virtual DiscriminatorBuilder HasValue<TEntity>([CanBeNull] object value)
/// <returns> The same builder so that multiple calls can be chained. </returns>
public virtual DiscriminatorBuilder HasValue([NotNull] Type entityType, [CanBeNull] object value)
{
var entityTypeBuilder =
EntityTypeBuilder.Metadata.IsQueryType
? EntityTypeBuilder.ModelBuilder.Query(
entityType, AnnotationsBuilder.ConfigurationSource)
: EntityTypeBuilder.ModelBuilder.Entity(
var entityTypeBuilder = EntityTypeBuilder.ModelBuilder.Entity(
entityType, AnnotationsBuilder.ConfigurationSource, owned: null);

return HasValue(entityTypeBuilder, value);
Expand All @@ -83,11 +79,7 @@ public virtual DiscriminatorBuilder HasValue([NotNull] Type entityType, [CanBeNu
/// <returns> The same builder so that multiple calls can be chained. </returns>
public virtual DiscriminatorBuilder HasValue([NotNull] string entityTypeName, [CanBeNull] object value)
{
var entityTypeBuilder =
EntityTypeBuilder.Metadata.IsQueryType
? EntityTypeBuilder.ModelBuilder.Query(
entityTypeName, AnnotationsBuilder.ConfigurationSource)
: EntityTypeBuilder.ModelBuilder.Entity(
var entityTypeBuilder = EntityTypeBuilder.ModelBuilder.Entity(
entityTypeName, AnnotationsBuilder.ConfigurationSource, owned: null);

return HasValue(entityTypeBuilder, value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public virtual InternalModelBuilder Apply(InternalModelBuilder modelBuilder)
Dictionary<string, Index> Indexes)>();
foreach (var entityType in modelBuilder.Metadata.GetEntityTypes())
{
if (entityType.IsQueryType)
if (entityType.IsKeyless)
{
continue;
}
Expand Down
4 changes: 2 additions & 2 deletions src/EFCore.Relational/Metadata/Internal/TableMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public virtual IEnumerable<IForeignKey> GetForeignKeys()
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.IsQueryType))
foreach (var entityType in model.GetEntityTypes().Where(et => et.FindPrimaryKey() != null))
{
var relationalExtentions = entityType.Relational();
var fullName = (relationalExtentions.Schema, relationalExtentions.TableName);
Expand All @@ -146,7 +146,7 @@ public static IReadOnlyList<TableMapping> GetTableMappings([NotNull] IModel mode
public static TableMapping GetTableMapping([NotNull] IModel model, [NotNull] string table, [CanBeNull] string schema)
{
var mappedEntities = new List<IEntityType>();
foreach (var entityType in model.GetEntityTypes().Where(et => !et.IsQueryType))
foreach (var entityType in model.GetEntityTypes().Where(et => et.FindPrimaryKey() != null))
{
var relationalExtentions = entityType.Relational();
if (table == relationalExtentions.TableName
Expand Down
2 changes: 1 addition & 1 deletion src/EFCore.Relational/Migrations/MigrationsSqlGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1648,7 +1648,7 @@ protected virtual IEnumerable<IEntityType> FindEntityTypes(
[CanBeNull] string schema,
[NotNull] string tableName)
=> model?.GetEntityTypes().Where(
t => t.Relational().TableName == tableName && t.Relational().Schema == schema && !t.IsQueryType);
t => t.Relational().TableName == tableName && t.Relational().Schema == schema && t.FindPrimaryKey() != null);

/// <summary>
/// <para>
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/EFCore.Relational/Properties/RelationalStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -477,8 +477,8 @@
<value>A SQL parameter or literal was generated for the type '{type}' using the ValueConverter '{valueConverter}'. Review the generated SQL for correctness and consider evaluating the target expression in-memory instead.</value>
<comment>Warning RelationalEventId.ValueConversionSqlLiteralWarning object object</comment>
</data>
<data name="DerivedQueryTypeView" xml:space="preserve">
<value>The query type '{queryType}' cannot be mapped to a view because it is derived from '{baseType}'. Only base query types can be mapped to a view.</value>
<data name="DerivedTypeTable" xml:space="preserve">
<value>The entity type '{entityType}' cannot be mapped to a table because it is derived from '{baseType}'. Only base entity types can be mapped to a table.</value>
</data>
<data name="RelationalCloneNotImplemented" xml:space="preserve">
<value>The '{mapping}' does not support 2.2 style type mapping. The database provider needs to be updated to support the full set of mapping customization.</value>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,15 @@ var materializerExpression
obj: null,
parameters: new object[]
{
_querySource, QueryModelVisitor.QueryCompilationContext.IsTrackingQuery
&& !entityType.IsQueryType,
entityType.FindPrimaryKey(), materializer, materializerExpression, typeIndexMap, QueryModelVisitor.QueryCompilationContext.IsQueryBufferRequired
&& !entityType.IsQueryType
_querySource,
QueryModelVisitor.QueryCompilationContext.IsTrackingQuery
&& entityType.FindPrimaryKey() != null,
entityType.FindPrimaryKey(),
materializer,
materializerExpression,
typeIndexMap,
QueryModelVisitor.QueryCompilationContext.IsQueryBufferRequired
&& entityType.FindPrimaryKey() != null
});
}
else
Expand Down Expand Up @@ -380,17 +385,16 @@ private void DiscriminateProjectionQuery(
{
Expression discriminatorPredicate;

if (entityType.IsQueryType)
if (entityType.FindPrimaryKey() == null)
{
discriminatorPredicate = GenerateDiscriminatorExpression(entityType, selectExpression, querySource);
}
else
{
var sharedTypes = new HashSet<IEntityType>(
_model.GetEntityTypes()
.Where(e => !e.IsQueryType)
.Where(
et => et.Relational().TableName == entityType.Relational().TableName
.Where(et => et.FindPrimaryKey() != null
&& et.Relational().TableName == entityType.Relational().TableName
&& et.Relational().Schema == entityType.Relational().Schema));

var currentPath = new Stack<IEntityType>();
Expand Down
75 changes: 75 additions & 0 deletions src/EFCore.Relational/RelationalEntityTypeBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,81 @@ public static EntityTypeBuilder<TEntity> ToTable<TEntity>(
where TEntity : class
=> (EntityTypeBuilder<TEntity>)ToTable((EntityTypeBuilder)entityTypeBuilder, name, schema);

/// <summary>
/// Configures the view or table that the view maps to when targeting a relational database.
/// </summary>
/// <param name="EntityTypeBuilder"> The builder for the query type being configured. </param>
/// <param name="name"> The name of the view or table. </param>
/// <returns> The same builder instance so that multiple calls can be chained. </returns>
[Obsolete("Use ToTable() instead")]
public static EntityTypeBuilder ToView(
[NotNull] this EntityTypeBuilder EntityTypeBuilder,
[CanBeNull] string name)
{
Check.NotNull(EntityTypeBuilder, nameof(EntityTypeBuilder));
Check.NullButNotEmpty(name, nameof(name));

EntityTypeBuilder.GetInfrastructure<InternalEntityTypeBuilder>()
.Relational(ConfigurationSource.Explicit)
.ToTable(name);

return EntityTypeBuilder;
}

/// <summary>
/// Configures the view or table that the view maps to when targeting a relational database.
/// </summary>
/// <typeparam name="TQuery"> The query type being configured. </typeparam>
/// <param name="EntityTypeBuilder"> The builder for the query type being configured. </param>
/// <param name="name"> The name of the view or table. </param>
/// <returns> The same builder instance so that multiple calls can be chained. </returns>
[Obsolete("Use ToTable() instead")]
public static EntityTypeBuilder<TQuery> ToView<TQuery>(
[NotNull] this EntityTypeBuilder<TQuery> EntityTypeBuilder,
[CanBeNull] string name)
where TQuery : class
=> (EntityTypeBuilder<TQuery>)ToView((EntityTypeBuilder)EntityTypeBuilder, name);

/// <summary>
/// Configures the view or table that the view maps to when targeting a relational database.
/// </summary>
/// <param name="EntityTypeBuilder"> The builder for the query type being configured. </param>
/// <param name="name"> The name of the view or table. </param>
/// <param name="schema"> The schema of the view or table. </param>
/// <returns> The same builder instance so that multiple calls can be chained. </returns>
[Obsolete("Use ToTable() instead")]
public static EntityTypeBuilder ToView(
[NotNull] this EntityTypeBuilder EntityTypeBuilder,
[CanBeNull] string name,
[CanBeNull] string schema)
{
Check.NotNull(EntityTypeBuilder, nameof(EntityTypeBuilder));
Check.NullButNotEmpty(name, nameof(name));
Check.NullButNotEmpty(schema, nameof(schema));

EntityTypeBuilder.GetInfrastructure<InternalEntityTypeBuilder>()
.Relational(ConfigurationSource.Explicit)
.ToTable(name, schema);

return EntityTypeBuilder;
}

/// <summary>
/// Configures the view or table that the view maps to when targeting a relational database.
/// </summary>
/// <typeparam name="TQuery"> The query type being configured. </typeparam>
/// <param name="EntityTypeBuilder"> The builder for the query type being configured. </param>
/// <param name="name"> The name of the view or table. </param>
/// <param name="schema"> The schema of the view or table. </param>
/// <returns> The same builder instance so that multiple calls can be chained. </returns>
[Obsolete("Use ToTable() instead")]
public static EntityTypeBuilder<TQuery> ToView<TQuery>(
[NotNull] this EntityTypeBuilder<TQuery> EntityTypeBuilder,
[CanBeNull] string name,
[CanBeNull] string schema)
where TQuery : class
=> (EntityTypeBuilder<TQuery>)ToView((EntityTypeBuilder)EntityTypeBuilder, name, schema);

/// <summary>
/// Configures the discriminator column used to identify which entity type each row in a table represents
/// when an inheritance hierarchy is mapped to a single table in a relational database.
Expand Down
Loading

0 comments on commit 0830c10

Please sign in to comment.