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

Fix for 21089. Allow multiple indexes on the same properties. #21115

Merged
merged 6 commits into from
Jun 4, 2020

Conversation

lajones
Copy link
Contributor

@lajones lajones commented Jun 2, 2020

Fixes #21089.

Name is now part of the identifier for an index. This allows multiple indexes over the same properties so long as they have different names.

Added suitable overloads for creating such an index, and added FindIndex overloads for finding them.

Index no longer allows HasName to manipulate that identifying name, but we do have a HasDatabaseName extension API which stores the name by which the user wants this index to be referred to in SQL as an annotation on the Index. This is helpful in situations such as an anonymous index has been created when creating a foreign key and the user wants to provide a name for that index in the database different from the one which would be generated automatically.

One issue: in EntityTypeBuilder the APIs for creating a nameless and named Index for a list of property names are contrasted below:

        public virtual IndexBuilder HasIndex([NotNull] params string[] propertyNames) { ... }
        public virtual IndexBuilder HasIndex([NotNull] string[] propertyNames, [CanBeNull] string name) { ... }

Note that the propertyNames parameter is a params parameter for nameless indexes, but cannot be so for named ones. The same issue affects EntityTypeBuilder<T>, however there it is more natural to use expressions to define the index properties anyway.

@lajones lajones requested a review from AndriySvyryd June 2, 2020 19:00
@lajones lajones self-assigned this Jun 2, 2020
@lajones lajones requested a review from ajcvickers June 2, 2020 19:01
@lajones
Copy link
Contributor Author

lajones commented Jun 3, 2020

@AndriySvyryd Overall I'm worried about separating the single concept of Index into two separate categories, named and unnamed, that we talk about separately.

Our reason for doing this is solely historical - we originally created indexes as unique on the list of properties they represented - this seemed like a good idea because that's what's important for helping speed up queries, the name was just a handy way of referring to it.

Now you're suggesting separating by name because SQL databases don't allow you to create multiple indexes with the same name on the same table. But, as I mentioned before, if we have Entity-Splitting it's quite possible that they could have the same name on different tables, despite the fact that both indexes would be on the same EntityType. And non-SQL databases can do whatever they want.

But I think customers will continue to see them as one concept and we run the risk that the split will seem artificial and illogical - after all they always had names on the database - so "unnamed" is solely an EF concept. I'd like to make sure that we can write understandable docs on how to use this.

@AndriySvyryd
Copy link
Member

@lajones At the fluent API level no separation is needed. The problem is in Metadata API where it's not as clear that FindIndex(propertyList) doesn't return the named indexes defined on propertyList. I think that calling this out in the method name clarifies this without breaking too many users, since only a small segment uses these APIs. But I don't feel strongly about this

@lajones
Copy link
Contributor Author

lajones commented Jun 3, 2020

At the fluent API level no separation is needed. The problem is in Metadata API where it's not as clear that FindIndex(propertyList) doesn't return the named indexes defined on propertyList. I think that calling this out in the method name clarifies this without breaking too many users, since only a small segment uses these APIs. But I don't feel strongly about this

Design meeting decision 6/3/2020 - we decided not to rename FindIndex but that we would update the docs to point out what this method does.

@lajones lajones requested a review from AndriySvyryd June 4, 2020 01:17
Copy link
Member

@AndriySvyryd AndriySvyryd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking better

src/EFCore/Metadata/Builders/EntityTypeBuilder.cs Outdated Show resolved Hide resolved
src/EFCore/Metadata/IEntityType.cs Outdated Show resolved Hide resolved
src/EFCore/Metadata/IMutableEntityType.cs Outdated Show resolved Hide resolved
src/EFCore/Metadata/Internal/EntityType.cs Outdated Show resolved Hide resolved
src/EFCore/Metadata/Internal/EntityType.cs Outdated Show resolved Hide resolved
src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs Outdated Show resolved Hide resolved
@lajones lajones requested a review from AndriySvyryd June 4, 2020 18:04
@lajones lajones merged commit 546547d into master Jun 4, 2020
@lajones lajones deleted the 20200601_Issue21089_02 branch June 4, 2020 21:00
@@ -19,34 +19,38 @@ namespace Microsoft.EntityFrameworkCore
public static class RelationalIndexExtensions
{
/// <summary>
/// Returns the name for this index.
/// Returns the name of the index on the database.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the database or on the database?

/// </returns>
IConventionIndexBuilder HasIndex(
[NotNull] IReadOnlyList<IConventionProperty> properties,
[NotNull] string name,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HasIndex everywhere else takes CanBeNull name.

=> AddIndex(
new[] { property }, configurationSource);
new[] { property }, name, configurationSource);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pass null value to a parameter which is marked as NotNull.

/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public Index(
[NotNull] IReadOnlyList<Property> properties,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation.

@smitpatel
Copy link
Member

What is overall decision on HasIndex which takes name? Is that name nullable or not? The changes in this PR has mismatch in various APIs over that parameter value.

@AndriySvyryd
Copy link
Member

Name should not be nullable in any API

@lajones
Copy link
Contributor Author

lajones commented Jun 4, 2020

Name should not be nullable in any API

Agree with @AndriySvyryd. They were originally, deliberately [CanBeNull], but decision was made in design meeting for them to be [NotNull]. The weird thing is I could swear I had updated most of the ones that are now still marked as [CanBeNull]?? Anyway I'll fix them in a separate PR.

@lajones
Copy link
Contributor Author

lajones commented Jun 4, 2020

PR #21138 addresses the comments above.

/// <returns> An object that can be used to configure the index. </returns>
public new virtual IndexBuilder<TEntity> HasIndex(
[NotNull] string[] propertyNames,
[CanBeNull] string name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here

/// <returns> An object that can be used to configure the index. </returns>
public virtual IndexBuilder<TEntity> HasIndex(
[NotNull] Expression<Func<TEntity, object>> indexExpression,
[CanBeNull] string name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here

/// <returns> An object that can be used to configure the index. </returns>
public virtual IndexBuilder HasIndex(
[NotNull] string[] propertyNames,
[CanBeNull] string name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here

/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual Index FindDeclaredIndex([NotNull] string name)
=> _namedIndexes.TryGetValue(name, out var index)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

null check

/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual IEnumerable<Index> FindIndexesInHierarchy([NotNull] string name)
=> ToEnumerable(FindIndex(name)).Concat(FindDerivedIndexes(name));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

null check

src/EFCore/Metadata/Internal/EntityType.cs Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow multiple indexes on the same properties
3 participants