Skip to content

Commit

Permalink
Index convention changes for non-relational providers (#34054)
Browse files Browse the repository at this point in the history
* Index convention changes for non-relational providers

Block unused indexes with the Cosmos provider. Fixes #34023.

Also stop adding indexes for foreign keys by convention for relational providers. Fixes #34053.

* Don't remove the index convention for non-relational providers.
  • Loading branch information
ajcvickers committed Jul 3, 2024
1 parent 97d2365 commit 9c2dc75
Show file tree
Hide file tree
Showing 41 changed files with 2,009 additions and 469 deletions.
23 changes: 23 additions & 0 deletions src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public override void Validate(IModel model, IDiagnosticsLogger<DbLoggerCategory.
ValidateKeys(model, logger);
ValidateSharedContainerCompatibility(model, logger);
ValidateOnlyETagConcurrencyToken(model, logger);
ValidateIndexes(model, logger);
}

/// <summary>
Expand Down Expand Up @@ -431,4 +432,26 @@ protected virtual void ValidateDatabaseProperties(
}
}
}

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
protected virtual void ValidateIndexes(
IModel model,
IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
{
foreach (var entityType in model.GetEntityTypes())
{
foreach (var index in entityType.GetDeclaredIndexes())
{
throw new InvalidOperationException(
CosmosStrings.IndexesExist(
entityType.DisplayName(),
string.Join(",", index.Properties.Select(e => e.Name))));
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.EntityFrameworkCore.Cosmos.Metadata.Internal;

namespace Microsoft.EntityFrameworkCore.Cosmos.Metadata.Conventions.Internal;

/// <summary>
Expand Down Expand Up @@ -37,6 +35,7 @@ public override ConventionSet CreateConventionSet()
conventionSet.Add(new ContextContainerConvention(Dependencies));
conventionSet.Add(new ETagPropertyConvention());
conventionSet.Add(new StoreKeyConvention(Dependencies));
conventionSet.Remove(typeof(ForeignKeyIndexConvention));

conventionSet.Replace<ValueGenerationConvention>(new CosmosValueGenerationConvention(Dependencies));
conventionSet.Replace<KeyDiscoveryConvention>(new CosmosKeyDiscoveryConvention(Dependencies));
Expand Down
8 changes: 8 additions & 0 deletions src/EFCore.Cosmos/Properties/CosmosStrings.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.Cosmos/Properties/CosmosStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@
<data name="IdNonStringStoreType" xml:space="preserve">
<value>The type of the '{idProperty}' property on '{entityType}' is '{propertyType}'. All 'id' properties must be strings or have a string value converter.</value>
</data>
<data name="IndexesExist" xml:space="preserve">
<value>The entity type '{entityType}' has an index defined over properties '{properties}'. The Azure Cosmos DB provider for EF Core currently does not support index definitions.</value>
</data>
<data name="InvalidDerivedTypeInEntityProjection" xml:space="preserve">
<value>The specified entity type '{derivedType}' is not derived from '{entityType}'.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public override ConventionSet CreateConventionSet()
var conventionSet = base.CreateConventionSet();

conventionSet.Add(new DefiningQueryRewritingConvention(Dependencies));
conventionSet.Remove(typeof(ForeignKeyIndexConvention));

return conventionSet;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ protected override void UseTransaction(DatabaseFacade facade, IDbContextTransact
{
}

protected override bool HasForeignKeyIndexes
=> false;

protected override async Task ExecuteWithStrategyInTransactionAsync(
Func<CustomTypesIdentityContext, Task> testOperation,
Func<CustomTypesIdentityContext, Task> nestedTestOperation1 = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ public class AspNetIdentityCustomTypesIntKeyInMemoryTest(AspNetIdentityCustomTyp
: AspNetIdentityCustomTypesIntKeyTestBase<
AspNetIdentityCustomTypesIntKeyInMemoryTest.AspNetIdentityCustomTypesIntKeyInMemoryFixture>(fixture)
{
protected override bool HasForeignKeyIndexes
=> false;

protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction)
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ namespace Microsoft.EntityFrameworkCore;
public class AspNetIdentityDefaultInMemoryTest(AspNetIdentityDefaultInMemoryTest.AspNetDefaultIdentityInMemoryFixture fixture)
: AspNetIdentityDefaultTestBase<AspNetIdentityDefaultInMemoryTest.AspNetDefaultIdentityInMemoryFixture>(fixture)
{
protected override bool HasForeignKeyIndexes
=> false;

protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction)
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ namespace Microsoft.EntityFrameworkCore;
public class AspNetIdentityIntKeyInMemoryTest(AspNetIdentityIntKeyInMemoryTest.AspNetIdentityIntKeyInMemoryFixture fixture)
: AspNetIdentityIntKeyTestBase<AspNetIdentityIntKeyInMemoryTest.AspNetIdentityIntKeyInMemoryFixture>(fixture)
{
protected override bool HasForeignKeyIndexes
=> false;

protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction)
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ namespace Microsoft.EntityFrameworkCore;
public class ConfigurationDbContextInMemoryTest(ConfigurationDbContextInMemoryTest.ConfigurationDbContextInMemoryFixture fixture)
: ConfigurationDbContextTestBase<ConfigurationDbContextInMemoryTest.ConfigurationDbContextInMemoryFixture>(fixture)
{
protected override bool HasForeignKeyIndexes
=> false;

protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction)
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ namespace Microsoft.EntityFrameworkCore;

public class GrpcInMemoryTest(GrpcInMemoryTest.GrpcInMemoryFixture fixture) : GrpcTestBase<GrpcInMemoryTest.GrpcInMemoryFixture>(fixture)
{
protected override bool HasForeignKeyIndexes
=> false;

public class GrpcInMemoryFixture : GrpcFixtureBase
{
protected override ITestStoreFactory TestStoreFactory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,9 @@ protected override List<EntityTypeMapping> ExpectedMappings
"Property: CustomRoleClaimString.Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd",
"Property: CustomRoleClaimString.ClaimType (string)",
"Property: CustomRoleClaimString.ClaimValue (string)",
"Property: CustomRoleClaimString.RoleId (string) Required FK Index",
$"Property: CustomRoleClaimString.RoleId (string) Required FK{(HasForeignKeyIndexes ? " Index" : "")}",
},
Indexes = { "{'RoleId'} ", },
Indexes = HasForeignKeyIndexes ? ["{'RoleId'} "] : [],
FKs =
{
"ForeignKey: CustomRoleClaimString {'RoleId'} -> CustomRoleString {'Id'} Required Cascade ToDependent: RoleClaims ToPrincipal: Role",
Expand Down Expand Up @@ -215,9 +215,9 @@ protected override List<EntityTypeMapping> ExpectedMappings
"Property: CustomUserClaimString.Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd",
"Property: CustomUserClaimString.ClaimType (string)",
"Property: CustomUserClaimString.ClaimValue (string)",
"Property: CustomUserClaimString.UserId (string) Required FK Index",
$"Property: CustomUserClaimString.UserId (string) Required FK{(HasForeignKeyIndexes ? " Index" : "")}",
},
Indexes = { "{'UserId'} ", },
Indexes = HasForeignKeyIndexes ? ["{'UserId'} "] : [],
FKs =
{
"ForeignKey: CustomUserClaimString {'UserId'} -> CustomUserString {'Id'} Required Cascade ToDependent: Claims ToPrincipal: User",
Expand All @@ -237,9 +237,9 @@ protected override List<EntityTypeMapping> ExpectedMappings
"Property: CustomUserLoginString.LoginProvider (string) Required PK AfterSave:Throw",
"Property: CustomUserLoginString.ProviderKey (string) Required PK AfterSave:Throw",
"Property: CustomUserLoginString.ProviderDisplayName (string)",
"Property: CustomUserLoginString.UserId (string) Required FK Index",
$"Property: CustomUserLoginString.UserId (string) Required FK{(HasForeignKeyIndexes ? " Index" : "")}",
},
Indexes = { "{'UserId'} ", },
Indexes = HasForeignKeyIndexes ? ["{'UserId'} "] : [],
FKs =
{
"ForeignKey: CustomUserLoginString {'UserId'} -> CustomUserString {'Id'} Required Cascade ToDependent: Logins ToPrincipal: User",
Expand All @@ -257,9 +257,9 @@ protected override List<EntityTypeMapping> ExpectedMappings
Properties =
{
"Property: CustomUserRoleString.UserId (string) Required PK FK AfterSave:Throw",
"Property: CustomUserRoleString.RoleId (string) Required PK FK Index AfterSave:Throw",
$"Property: CustomUserRoleString.RoleId (string) Required PK FK{(HasForeignKeyIndexes ? " Index" : "")} AfterSave:Throw",
},
Indexes = { "{'RoleId'} ", },
Indexes = HasForeignKeyIndexes ? ["{'RoleId'} "] : [],
FKs =
{
"ForeignKey: CustomUserRoleString {'RoleId'} -> CustomRoleString {'Id'} Required Cascade ToDependent: UserRoles ToPrincipal: Role",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ protected override List<EntityTypeMapping> ExpectedMappings
"Property: CustomRoleClaimInt.Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd",
"Property: CustomRoleClaimInt.ClaimType (string)",
"Property: CustomRoleClaimInt.ClaimValue (string)",
"Property: CustomRoleClaimInt.RoleId (int) Required FK Index",
$"Property: CustomRoleClaimInt.RoleId (int) Required FK{(HasForeignKeyIndexes ? " Index" : "")}",
},
Indexes = { "{'RoleId'} ", },
Indexes = HasForeignKeyIndexes ? ["{'RoleId'} "] : [],
FKs = { "ForeignKey: CustomRoleClaimInt {'RoleId'} -> CustomRoleInt {'Id'} Required Cascade", },
},
new EntityTypeMapping
Expand All @@ -87,9 +87,9 @@ protected override List<EntityTypeMapping> ExpectedMappings
"Property: CustomUserClaimInt.Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd",
"Property: CustomUserClaimInt.ClaimType (string)",
"Property: CustomUserClaimInt.ClaimValue (string)",
"Property: CustomUserClaimInt.UserId (int) Required FK Index",
$"Property: CustomUserClaimInt.UserId (int) Required FK{(HasForeignKeyIndexes ? " Index" : "")}",
},
Indexes = { "{'UserId'} ", },
Indexes = HasForeignKeyIndexes ? ["{'UserId'} "] : [],
FKs = { "ForeignKey: CustomUserClaimInt {'UserId'} -> CustomUserInt {'Id'} Required Cascade ToDependent: Claims", },
},
new EntityTypeMapping
Expand Down Expand Up @@ -138,9 +138,9 @@ protected override List<EntityTypeMapping> ExpectedMappings
"Property: CustomUserLoginInt.LoginProvider (string) Required PK AfterSave:Throw",
"Property: CustomUserLoginInt.ProviderKey (string) Required PK AfterSave:Throw",
"Property: CustomUserLoginInt.ProviderDisplayName (string)",
"Property: CustomUserLoginInt.UserId (int) Required FK Index",
$"Property: CustomUserLoginInt.UserId (int) Required FK{(HasForeignKeyIndexes ? " Index" : "")}",
},
Indexes = { "{'UserId'} ", },
Indexes = HasForeignKeyIndexes ? ["{'UserId'} "] : [],
FKs = { "ForeignKey: CustomUserLoginInt {'UserId'} -> CustomUserInt {'Id'} Required Cascade ToDependent: Logins", },
},
new EntityTypeMapping
Expand All @@ -151,9 +151,9 @@ protected override List<EntityTypeMapping> ExpectedMappings
Properties =
{
"Property: CustomUserRoleInt.UserId (int) Required PK FK AfterSave:Throw",
"Property: CustomUserRoleInt.RoleId (int) Required PK FK Index AfterSave:Throw",
$"Property: CustomUserRoleInt.RoleId (int) Required PK FK{(HasForeignKeyIndexes ? " Index" : "")} AfterSave:Throw",
},
Indexes = { "{'RoleId'} ", },
Indexes = HasForeignKeyIndexes ? ["{'RoleId'} "] : [],
FKs =
{
"ForeignKey: CustomUserRoleInt {'RoleId'} -> CustomRoleInt {'Id'} Required Cascade",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ protected override List<EntityTypeMapping> ExpectedMappings
"Property: IdentityRoleClaim<string>.Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd",
"Property: IdentityRoleClaim<string>.ClaimType (string)",
"Property: IdentityRoleClaim<string>.ClaimValue (string)",
"Property: IdentityRoleClaim<string>.RoleId (string) Required FK Index",
$"Property: IdentityRoleClaim<string>.RoleId (string) Required FK{(HasForeignKeyIndexes ? " Index" : "")}",
},
Indexes = { "{'RoleId'} ", },
Indexes = HasForeignKeyIndexes ? ["{'RoleId'} "] : [],
FKs = { "ForeignKey: IdentityRoleClaim<string> {'RoleId'} -> IdentityRole {'Id'} Required Cascade", },
},
new EntityTypeMapping
Expand Down Expand Up @@ -87,9 +87,9 @@ protected override List<EntityTypeMapping> ExpectedMappings
"Property: IdentityUserClaim<string>.Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd",
"Property: IdentityUserClaim<string>.ClaimType (string)",
"Property: IdentityUserClaim<string>.ClaimValue (string)",
"Property: IdentityUserClaim<string>.UserId (string) Required FK Index",
$"Property: IdentityUserClaim<string>.UserId (string) Required FK{(HasForeignKeyIndexes ? " Index" : "")}",
},
Indexes = { "{'UserId'} ", },
Indexes = HasForeignKeyIndexes ? ["{'UserId'} "] : [],
FKs = { "ForeignKey: IdentityUserClaim<string> {'UserId'} -> IdentityUser {'Id'} Required Cascade", },
},
new EntityTypeMapping
Expand All @@ -102,9 +102,9 @@ protected override List<EntityTypeMapping> ExpectedMappings
"Property: IdentityUserLogin<string>.LoginProvider (string) Required PK AfterSave:Throw",
"Property: IdentityUserLogin<string>.ProviderKey (string) Required PK AfterSave:Throw",
"Property: IdentityUserLogin<string>.ProviderDisplayName (string)",
"Property: IdentityUserLogin<string>.UserId (string) Required FK Index",
$"Property: IdentityUserLogin<string>.UserId (string) Required FK{(HasForeignKeyIndexes ? " Index" : "")}",
},
Indexes = { "{'UserId'} ", },
Indexes = HasForeignKeyIndexes ? ["{'UserId'} "] : [],
FKs = { "ForeignKey: IdentityUserLogin<string> {'UserId'} -> IdentityUser {'Id'} Required Cascade", },
},
new EntityTypeMapping
Expand All @@ -115,9 +115,9 @@ protected override List<EntityTypeMapping> ExpectedMappings
Properties =
{
"Property: IdentityUserRole<string>.UserId (string) Required PK FK AfterSave:Throw",
"Property: IdentityUserRole<string>.RoleId (string) Required PK FK Index AfterSave:Throw",
$"Property: IdentityUserRole<string>.RoleId (string) Required PK FK{(HasForeignKeyIndexes ? " Index" : "")} AfterSave:Throw",
},
Indexes = { "{'RoleId'} ", },
Indexes = HasForeignKeyIndexes ? ["{'RoleId'} "] : [],
FKs =
{
"ForeignKey: IdentityUserRole<string> {'RoleId'} -> IdentityRole {'Id'} Required Cascade",
Expand Down
Loading

0 comments on commit 9c2dc75

Please sign in to comment.