Skip to content

Commit

Permalink
Throw if defining query is used on keyed entity type
Browse files Browse the repository at this point in the history
Fixes #17157
  • Loading branch information
ajcvickers committed Aug 19, 2019
1 parent 8d79f6d commit 30bab91
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 9 deletions.
32 changes: 26 additions & 6 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 @@ -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.DefiningQueryAndKey(entityType.DisplayName()));
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/EFCore/Properties/CoreStrings.Designer.cs

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

3 changes: 3 additions & 0 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="DefiningQueryAndKey" 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
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.DefiningQueryAndKey("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

0 comments on commit 30bab91

Please sign in to comment.