Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throw if defining query is used on keyed entity type #17248

Merged
merged 1 commit into from
Aug 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions src/EFCore/Infrastructure/ModelValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public virtual void Validate(IModel model, IDiagnosticsLogger<DbLoggerCategory.M
ValidateFieldMapping(model, logger);
ValidateKeylessTypes(model, logger);
ValidateQueryFilters(model, logger);
ValidateDefiningQuery(model, logger);
ValidateData(model, logger);
LogShadowProperties(model, logger);
}
Expand Down Expand Up @@ -811,7 +812,7 @@ protected virtual void ValidateKeylessTypes([NotNull] IModel model, [NotNull] ID
if (entityType.FindPrimaryKey() != null)
{
throw new InvalidOperationException(
CoreStrings.NonKeylessEntityTypeDefiningQuery(entityType.DisplayName()));
CoreStrings.DefiningQueryWithKey(entityType.DisplayName()));
}
}
}
Expand All @@ -828,13 +829,32 @@ protected virtual void ValidateQueryFilters([NotNull] IModel model, [NotNull] ID

foreach (var entityType in model.GetEntityTypes())
{
if (entityType.GetQueryFilter() != null)
if (entityType.GetQueryFilter() != null
&& entityType.BaseType != null)
{
if (entityType.BaseType != null)
{
throw new InvalidOperationException(
CoreStrings.BadFilterDerivedType(entityType.GetQueryFilter(), entityType.DisplayName()));
}
throw new InvalidOperationException(
CoreStrings.BadFilterDerivedType(entityType.GetQueryFilter(), entityType.DisplayName()));
}
}
}

/// <summary>
/// Validates the mapping/configuration of defining queries in the model.
/// </summary>
/// <param name="model"> The model to validate. </param>
/// <param name="logger"> The logger to use. </param>
protected virtual void ValidateDefiningQuery(
[NotNull] IModel model, [NotNull] IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
{
Check.NotNull(model, nameof(model));

foreach (var entityType in model.GetEntityTypes())
{
if (entityType.GetDefiningQuery() != null
&& entityType.FindPrimaryKey() != null)
{
throw new InvalidOperationException(
CoreStrings.DefiningQueryWithKey(entityType.DisplayName()));
}
}
}
Expand Down
16 changes: 8 additions & 8 deletions src/EFCore/Properties/CoreStrings.Designer.cs

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

6 changes: 3 additions & 3 deletions src/EFCore/Properties/CoreStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +891,9 @@
<data name="BadFilterDerivedType" xml:space="preserve">
<value>The filter expression '{filter}' cannot be specified for entity type '{entityType}'. A filter may only be applied to the root entity type in a hierarchy.</value>
</data>
<data name="DefiningQueryWithKey" xml:space="preserve">
<value>The entity type '{entityType}' cannot use 'ToQuery' to create a defining query because it also defines a primary key. Defining queries can only be used to back entity types without keys.</value>
</data>
<data name="ConverterPropertyMismatch" xml:space="preserve">
<value>Converter for model type '{converterType}' cannot be used for '{entityType}.{propertyName}' because its type is '{propertyType}'.</value>
</data>
Expand Down Expand Up @@ -1120,9 +1123,6 @@
<data name="InvalidSetKeylessOperation" xml:space="preserve">
<value>The invoked method is cannot be used for the entity type '{entityType}' because it does not have a primary key.</value>
</data>
<data name="NonKeylessEntityTypeDefiningQuery" xml:space="preserve">
<value>The entity type '{entityType}' cannot have a defining query because it has a primary key. Only keyless entity types can have a defining query.</value>
</data>
<data name="DerivedEntityTypeHasNoKey" xml:space="preserve">
<value>A '{derivedType}' cannot be configured as keyless because it is a derived type. The root type '{rootType}' must be configured as keyless. If you did not intend for '{rootType}' to be included in the model, ensure that it is not included in a DbSet property on your context, referenced in a configuration call to ModelBuilder, or referenced from a navigation property on a type that is included in the model.</value>
</data>
Expand Down
9 changes: 9 additions & 0 deletions test/EFCore.Tests/Infrastructure/ModelValidatorTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ public virtual void Detects_filter_on_derived_type()
VerifyError(CoreStrings.BadFilterDerivedType(entityTypeD.GetQueryFilter(), entityTypeD.DisplayName()), modelBuilder.Model);
}

[ConditionalFact]
public virtual void Detects_defining_query_on_keyed_entity_type()
{
var modelBuilder = CreateConventionalModelBuilder();
modelBuilder.Entity<A>().ToQuery(() => new List<A>().AsQueryable());

VerifyError(CoreStrings.DefiningQueryWithKey("A"), modelBuilder.Model);
}

[ConditionalFact]
public virtual void Detects_shadow_entities()
{
Expand Down
3 changes: 0 additions & 3 deletions test/EFCore.Tests/Metadata/Internal/EntityTypeTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,9 @@ private class FakeEntityType : IEntityType
public string Name { get; }
public Type ClrType { get; }
public IEntityType BaseType { get; }
public bool IsKeyless { get; }
public string DefiningNavigationName { get; }
public IEntityType DefiningEntityType { get; }
public LambdaExpression QueryFilter { get; }
public LambdaExpression DefiningQuery { get; }
public bool IsQueryType { get; }
public IKey FindPrimaryKey() => throw new NotImplementedException();
public IKey FindKey(IReadOnlyList<IProperty> properties) => throw new NotImplementedException();
public IEnumerable<IKey> GetKeys() => throw new NotImplementedException();
Expand Down