Skip to content

feat(Migrations): SQL Server Filterable indexes.#6866

Merged
AndriySvyryd merged 1 commit intodotnet:feature/1.2.0from
laskoviymishka:feat/FiltrableIndexes
Oct 29, 2016
Merged

feat(Migrations): SQL Server Filterable indexes.#6866
AndriySvyryd merged 1 commit intodotnet:feature/1.2.0from
laskoviymishka:feat/FiltrableIndexes

Conversation

@laskoviymishka
Copy link
Copy Markdown
Contributor

Please check if the PR fulfills these requirements

  • The code builds and tests pass (verified by our automated build checks)
  • Commit messages follow this format
    Implement ability to add filter to index
    - Extension for index builder
    - Index creation operation
    - Corresponding SQL generator for migration
    - Corresponding SQL reverse engeniering code for scaffolding
    - Corresponding C# reverse engeniering code for scaffolding

    Fixes #5817

Please review the guidelines for CONTRIBUTING.md for more details.
Fixed #5817

Copy link
Copy Markdown
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.

In addition to the below comments please rebase on feature/1.2.0 and run build.cmd

public virtual string Name { get; [param: NotNull] set; }
public virtual ICollection<IndexColumnModel> IndexColumns { get; [param: NotNull] set; } = new List<IndexColumnModel>();
public virtual bool IsUnique { get; [param: NotNull] set; }
public virtual string WhereClauses { get; set; }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Add [param: CanBeNull]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Any reason this is plural? Am not familiar with SQL Server here but in PostgreSQL it's just a standard single WHERE clause

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This should be renamed in Filter. Just forgot this entry.

[CanBeNull] string schema = null,
bool unique = false)
bool unique = false,
string filter = null)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Add [CanBeNull]

[CanBeNull] string schema = null,
bool unique = false)
bool unique = false,
string filter = null)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Add [CanBeNull]


/// <summary>
/// Gets the properties that this index is defined on.
/// </summary>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Filtered indexes are a SQL Server feature, so it should be stored as an annotation using extension methods. See how .IsClustered is implemented.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

On a second though, other relational providers support it so it can go in .Relational

Sql);
}

public override void CreateIndexOperation_with_whrere_clauses()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Typo

IsUnique = false
});

[Fact]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Typo

Name = "IX_People_Name",
Table = "People",
Columns = new[] { "Name" },
IsUnique = false,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is SQLServer-specific SQL in a provider-independent test. However, it's not terribly important as this is only a unit test (i.e. the SQL never gets sent/evaluated), so no real harm.

Sql);
}

[Fact]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shouldn't this test simply override CreateIndexOperation_with_where_clauses, defined in MigrationSqlGeneratorTestBase.cs?

Sql);
}

[Fact]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should probably be defined in MigrationSqlGeneratorTestBase.cs and overridden here (useful for other providers)

@laskoviymishka laskoviymishka changed the base branch from dev to feature/1.2.0 October 27, 2016 12:26
@laskoviymishka
Copy link
Copy Markdown
Contributor Author

@AndriySvyryd please review latest check-in. I moved it into relational annotation but not completely sure that this proper way to use realational attributes (i tried to mimic HasName behaivior).

Copy link
Copy Markdown
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.

You also need to add a method to RelationalIndexBuilderAnnotations so filters can be set by conventions, as well as in SqlServerIndexBuilderAnnotations that would allow to set a filter just for SQL Server in case multiple providers are used with the same model.

/// <summary>
/// Gets a value indicating whre clauses to specific index.
/// </summary>
string Filter { get; set; }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The properties on this interface should be read-only.
Also the fix typos in the comment or just remove it.

&& s.Properties.Select(diffContext.FindTarget).SequenceEqual(t.Properties),
// ReSharper disable once ImplicitlyCapturedClosure
(s, t) => s.IsUnique == t.IsUnique
&& s.Relational().Filter == t.Relational().Filter
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You need to use Annotations.For(t).Filter in all of the migrations code, this allows it to read the provider-specific value

Table = Annotations.For(index.DeclaringEntityType).TableName,
Columns = index.Properties.Select(p => Annotations.For(p).ColumnName).ToArray()
Columns = index.Properties.Select(p => Annotations.For(p).ColumnName).ToArray(),
Filter = index.Relational().Filter
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Use Annotations.For

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You missed this one :)

@laskoviymishka
Copy link
Copy Markdown
Contributor Author

@AndriySvyryd done. Please review

<ProjectReference Include="..\..\src\Microsoft.EntityFrameworkCore.Relational\Microsoft.EntityFrameworkCore.Relational.csproj">
<Project>{6A25DF99-2615-46D8-9532-821764647EE1}</Project>
<Name>Microsoft.EntityFrameworkCore.Relational</Name>
</ProjectReference>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This project shouldn't reference .Relational



[Fact]
public void Can_write_index_builder_extension_with_where_clauses()
Copy link
Copy Markdown
Member

@AndriySvyryd AndriySvyryd Oct 27, 2016

Choose a reason for hiding this comment

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

Move this to RelationalBuilderExtensionsTest and add a similar test to RelationalMetadataExtensionsTest

@divega
Copy link
Copy Markdown
Contributor

divega commented Oct 27, 2016

General question about this PR: currently by default we add the filter WHERE x IS NOT NULL for unique indexes in SQL Server (not sure what we do for SQLite). Can that become a convention that takes advantage of this feature?

@AndriySvyryd
Copy link
Copy Markdown
Member

@divega Sure, I can do it after this is merged

Annotations.For(t).Name,
StringComparison.OrdinalIgnoreCase)
&& s.IsUnique == t.IsUnique
&& Annotations.For(s).Filter == Annotations.For(t).Filter
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@AndriySvyryd May be HasDifferences can handle this comparing? It looks like i can remove this lines

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

HasDifferences diffs migrations annotations, while they have the same API they are different from model annotations, the added conditions are still needed.

@laskoviymishka
Copy link
Copy Markdown
Contributor Author

@AndriySvyryd done, please review

Copy link
Copy Markdown
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.

Almost there.
After making the change below rebase again on the latest feature/1.2.0 and squash the commits

Annotations.For(t).Name,
StringComparison.OrdinalIgnoreCase)
&& s.IsUnique == t.IsUnique
&& Annotations.For(s).Filter == Annotations.For(t).Filter
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

HasDifferences diffs migrations annotations, while they have the same API they are different from model annotations, the added conditions are still needed.

/// <summary>
/// Gets a value indicating whre clauses to specific index.
/// </summary>
public string Filter
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This needs to be virtual. Also correct spelling in the comment or just remove it.


if (Index.Relational().Filter != null)
{
lines.Add("." + nameof(RelationalIndexBuilderExtensions.HasFilter) + "(\"" + Index.Relational().Filter + "\")");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

String interpolation?

/// </summary>
public new virtual bool Name([CanBeNull] string value) => SetName(value);

/// <summary>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should be HasFilter?

protected abstract IMigrationsSqlGenerator SqlGenerator { get; }

protected virtual string Sql { get; set; }
[Fact]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Missing empty line

@laskoviymishka
Copy link
Copy Markdown
Contributor Author

@AndriySvyryd @roji done, please review.

@roji
Copy link
Copy Markdown
Member

roji commented Oct 29, 2016

LGTM

@AndriySvyryd AndriySvyryd merged commit 2e0498a into dotnet:feature/1.2.0 Oct 29, 2016
@AndriySvyryd
Copy link
Copy Markdown
Member

Thank you for your contribution.

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.

5 participants