I use EF 6.1.x Code First.
I have read that an Index with Filter Expression is not supported by EF latest.
There is also no solution on SO:
One year later, what is the working way to make a Filter Index work with Code First and DbMigrations?
CREATE UNIQUE NONCLUSTERED INDEX [IX_DefaultLanguageApplicationId] ON [dbo].[Languages]
(
[IsDefaultLanguage] ASC,
[ApplicationId] ASC,
)
WHERE ([IsDefaultLanguage]=(1))
Please note that right now EF core 2.1.X added built in support for filtered indexes via the
HasFilter
extension on theIndexBuilder
, so a custom implementation is not required anymore.See this for more details
I know that the original post referred to the 6.1 version of EF, but after some research I have found a way to add an extension method for filtered indexes to the fluent api of EF Core (1.1 version). Maybe someone will find this useful (and maybe there is a way to implement this also in older versions). I have to warn you though. As this solution uses classes from within
Microsoft.EntityFrameworkCore.Migrations.Internal
andMicrosoft.EntityFrameworkCore.Infrastructure
namespaces, it’s no guaranteed that this code will work after EF gets updated. There is a massage included in a summary of each class within these namespaces saying that, so you have been warned.
But to the point.
First you have to create a standard extension method for the
IndexBuilder
. Its main responsibility is going to be adding a new annotation with the condition to the constructed index. One will use this method afterwards with the fluent api. Lest call our annotationSqlServer:FilteredIndex
.Next you have to allow this annotation to be actually included inside migrations. You have to override the default behavior of
SqlServerMigrationsAnnotationProvider
for index builders.Now comes the most difficult part. We have to override the default behavior of
SqlServerMigrationsSqlGenerator
regarding indexes.As you can see, we are calling the base generator here, so our condition will be added at the end of it without altering it. We have to remember not to terminate the base SQL statement here (last argument passed to the
base.Generate
method isfalse
). If our annotation is set we can append its value after theWHERE
clause at the end of the SQL statement. After that, depending on the argument passed to this method, we can finally terminate the statement or leave it as it is.For all those parts to work we have to replace old services with their new versions by overriding the
OnConfiguring
method of ourDbContext
.Now we can use our extension method like this:
It will generate migration like this:
And after calling
Script-Migration
commad in Package Manager Console we will see a resulting SQL as this:This method can actually be used to include any custom SQL generator into ef core fluent api. At least as long as the EF API remains the same.
In EF 6.1, the working way to make the this work with Code First and DbMigrations is to use the
Sql
method in theDbMigration
class:But I realise that you are probably asking if you can create an index using the IndexAttribute introduced in 6.1, but with an Filter - the answer to that is "No"
Almost a duplicate of: Entity Framework 6.1 - Create index with INCLUDE statement