Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,14 @@ protected virtual void Generate([NotNull] CreateIndexOperation operation, [NotNu
.Append("unique: true");
}

if (operation.Filter != null)
{
builder
.AppendLine(",")
.Append("filter: ")
.Append(operation.Filter);
}

builder.Append(")");

Annotations(operation.GetAnnotations(), builder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ protected virtual void GenerateIndex(

stringBuilder
.AppendLine()
.Append("b.HasIndex(")
.Append($"b.{nameof(EntityTypeBuilder.HasIndex)}(")
.Append(string.Join(", ", index.Properties.Select(p => _code.Literal(p.Name))))
.Append(")");

Expand All @@ -341,7 +341,14 @@ protected virtual void GenerateIndex(
{
stringBuilder
.AppendLine()
.Append(".IsUnique()");
.Append($".{nameof(IndexBuilder.IsUnique)}()");
}

if (index.Relational().Filter != null)
{
stringBuilder
.AppendLine()
.Append($".{nameof(RelationalIndexBuilderExtensions.HasFilter)}({index.Relational().Filter})");
}

var annotations = index.GetAnnotations().ToList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,17 @@ public virtual ICollection<string> FluentApiLines

if (!string.IsNullOrEmpty(Index.Relational().Name))
{
lines.Add("." + nameof(RelationalIndexBuilderExtensions.HasName) + "("
+ CSharpUtilities.Instance.DelimitString(Index.Relational().Name) + ")");
lines.Add($".{nameof(RelationalIndexBuilderExtensions.HasName)}({CSharpUtilities.Instance.DelimitString(Index.Relational().Name)})");
}

if (Index.IsUnique)
{
lines.Add("." + nameof(IndexBuilder.IsUnique) + "()");
lines.Add($".{nameof(IndexBuilder.IsUnique)}()");
}

if (Index.Relational().Filter != null)
{
lines.Add($".{nameof(RelationalIndexBuilderExtensions.HasFilter)}(\"{Index.Relational().Filter}\")");
}

return lines;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ public class IndexModel : Annotatable
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 Filter { get; [param: CanBeNull] set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Utilities;
using Microsoft.Extensions.Logging;
using Microsoft.EntityFrameworkCore.Extensions;

namespace Microsoft.EntityFrameworkCore.Scaffolding
{
Expand Down Expand Up @@ -423,7 +424,7 @@ protected virtual IndexBuilder VisitIndex([NotNull] EntityTypeBuilder builder, [
var primaryKeyColumns = index.Table.Columns
.Where(c => c.PrimaryKeyOrdinal.HasValue)
.OrderBy(c => c.PrimaryKeyOrdinal);
if (columnNames.SequenceEqual(primaryKeyColumns.Select(c => c.Name)))
if (columnNames.SequenceEqual(primaryKeyColumns.Select(c => c.Name)) && index.Filter == null)
{
// index is supporting the primary key. So there is no need for
// an extra index in the model. But if the index name does not
Expand All @@ -445,6 +446,11 @@ protected virtual IndexBuilder VisitIndex([NotNull] EntityTypeBuilder builder, [
var indexBuilder = builder.HasIndex(propertyNames)
.IsUnique(index.IsUnique);

if (index.Filter != null)
{
indexBuilder.HasFilter(index.Filter);
}

if (!string.IsNullOrEmpty(index.Name))
{
indexBuilder.HasName(index.Name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ namespace Microsoft.EntityFrameworkCore.Metadata
public interface IRelationalIndexAnnotations
{
string Name { get; }

string Filter { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,11 @@ public static class RelationalAnnotationNames
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public const string DiscriminatorValue = "DiscriminatorValue";

/// <summary>
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public const string Filter = "Filter";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ protected RelationalFullAnnotationNames(string prefix)
SequencePrefix = prefix + RelationalAnnotationNames.SequencePrefix;
DiscriminatorProperty = prefix + RelationalAnnotationNames.DiscriminatorProperty;
DiscriminatorValue = prefix + RelationalAnnotationNames.DiscriminatorValue;
Filter = prefix + RelationalAnnotationNames.Filter;
}

/// <summary>
Expand Down Expand Up @@ -96,6 +97,12 @@ protected RelationalFullAnnotationNames(string prefix)
/// </summary>
public readonly string Name;

/// <summary>
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public readonly string Filter;

/// <summary>
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,11 @@ public RelationalIndexBuilderAnnotations(
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public virtual bool HasName([CanBeNull] string value) => SetName(value);

/// <summary>
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public virtual bool HasFilter([CanBeNull] string value) => SetFilter(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,21 @@ public virtual string Name
[param: CanBeNull] set { SetName(value); }
}

public virtual string Filter
{
get
{
return (string)Annotations.GetAnnotation(RelationalFullAnnotationNames.Instance.Filter, ProviderFullAnnotationNames?.Filter);
}
[param: CanBeNull] set { SetFilter(value); }
}

protected virtual bool SetFilter([CanBeNull] string value)
=> Annotations.SetAnnotation(
RelationalFullAnnotationNames.Instance.Filter,
ProviderFullAnnotationNames?.Filter,
Check.NullButNotEmpty(value, nameof(value)));

protected virtual bool SetName([CanBeNull] string value)
=> Annotations.SetAnnotation(
RelationalFullAnnotationNames.Instance.Name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -973,10 +973,12 @@ protected virtual IEnumerable<MigrationOperation> Diff(
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.

&& !HasDifferences(MigrationsAnnotations.For(s), MigrationsAnnotations.For(t))
&& s.Properties.Select(diffContext.FindTarget).SequenceEqual(t.Properties),
// ReSharper disable once ImplicitlyCapturedClosure
(s, t) => s.IsUnique == t.IsUnique
&& Annotations.For(s).Filter == Annotations.For(t).Filter
&& !HasDifferences(MigrationsAnnotations.For(s), MigrationsAnnotations.For(t))
&& s.Properties.Select(diffContext.FindTarget).SequenceEqual(t.Properties));

Expand Down Expand Up @@ -1022,7 +1024,8 @@ protected virtual IEnumerable<MigrationOperation> Add(
Schema = targetEntityTypeAnnotations.Schema,
Table = targetEntityTypeAnnotations.TableName,
Columns = GetColumns(target.Properties),
IsUnique = target.IsUnique
IsUnique = target.IsUnique,
Filter = Annotations.For(target).Filter
};
operation.AddAnnotations(MigrationsAnnotations.For(target));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,20 +300,23 @@ public virtual OperationBuilder<CreateIndexOperation> CreateIndex(
[NotNull] string table,
[NotNull] string column,
[CanBeNull] string schema = null,
bool unique = false)
bool unique = false,
[CanBeNull] string filter = null)
=> CreateIndex(
name,
table,
new[] { column },
schema,
unique);
unique,
filter);

public virtual OperationBuilder<CreateIndexOperation> CreateIndex(
[NotNull] string name,
[NotNull] string table,
[NotNull] string[] columns,
[CanBeNull] string schema = null,
bool unique = false)
bool unique = false,
[CanBeNull] string filter = null)
{
Check.NotEmpty(name, nameof(name));
Check.NotEmpty(table, nameof(table));
Expand All @@ -325,7 +328,8 @@ public virtual OperationBuilder<CreateIndexOperation> CreateIndex(
Table = table,
Name = name,
Columns = columns,
IsUnique = unique
IsUnique = unique,
Filter = filter
};
Operations.Add(operation);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,13 @@ protected virtual void Generate(
.Append(ColumnList(operation.Columns))
.Append(")");

if (operation.Filter != null)
{
builder
.Append(" WHERE ")
.Append(operation.Filter);
}

if (terminate)
{
builder.AppendLine(SqlGenerationHelper.StatementTerminator);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ public class CreateIndexOperation : MigrationOperation
public virtual string Schema { get; [param: CanBeNull] set; }
public virtual string Table { get; [param: NotNull] set; }
public virtual string[] Columns { get; [param: NotNull] set; }
public virtual string Filter { get; [param: NotNull] set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,20 @@ public static IndexBuilder HasName([NotNull] this IndexBuilder indexBuilder, [Ca

return indexBuilder;
}

/// <summary>
/// Determines whether the specified index has filter expression.
/// </summary>
/// <param name="indexBuilder"> The builder for the index being configured. </param>
/// <param name="filterExpression"> The filter expression for the index. </param>
/// <returns>A builder to further configure the index. </returns>
public static IndexBuilder HasFilter([NotNull] this IndexBuilder indexBuilder, [NotNull] string filterExpression)
{
Check.NotEmpty(filterExpression, nameof(filterExpression));

indexBuilder.Metadata.Relational().Filter = filterExpression;

return indexBuilder;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,9 @@ private void GetIndexes()
i.is_unique,
c.name AS [column_name],
i.type_desc,
ic.key_ordinal
ic.key_ordinal,
i.has_filter,
i.filter_definition
FROM sys.indexes i
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND c.column_id = ic.column_id
Expand All @@ -471,6 +473,8 @@ AND object_name(i.object_id) <> '" + HistoryRepository.DefaultTableName + @"'" +
var typeDesc = reader.GetValueOrDefault<string>("type_desc");
var columnName = reader.GetValueOrDefault<string>("column_name");
var indexOrdinal = reader.GetValueOrDefault<byte>("key_ordinal");
var hasFilter = reader.GetValueOrDefault<bool>("has_filter");
var filterDefinition = reader.GetValueOrDefault<string>("filter_definition");

Logger.LogDebug(
RelationalDesignEventId.FoundIndexColumn,
Expand Down Expand Up @@ -513,7 +517,8 @@ AND object_name(i.object_id) <> '" + HistoryRepository.DefaultTableName + @"'" +
{
Table = table,
Name = indexName,
IsUnique = isUnique
IsUnique = isUnique,
Filter = hasFilter ? filterDefinition : null
};
index.SqlServer().IsClustered = typeDesc == "CLUSTERED";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ public SqlServerIndexBuilderAnnotations(
/// </summary>
public new virtual bool Name([CanBeNull] string value) => SetName(value);

/// <summary>
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public new virtual bool HasFilter([CanBeNull] string value) => SetFilter(value);

/// <summary>
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1035,7 +1035,8 @@ protected virtual void CreateIndexes(
Name = Annotations.For(index).Name,
Schema = Annotations.For(index.DeclaringEntityType).Schema,
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 = Annotations.For(index).Filter
};
operation.AddAnnotations(_migrationsAnnotations.For(index));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,23 @@ namespace Microsoft.EntityFrameworkCore.Relational.Tests.Metadata
{
public class RelationalBuilderExtensionsTest
{
[Fact]
public void Can_write_index_builder_extension_with_where_clauses()
{
var builder = CreateConventionModelBuilder();

var returnedBuilder = builder
.Entity<Customer>()
.HasIndex(e => e.Id)
.HasFilter("[Id] % 2 = 0");

Assert.IsType<IndexBuilder>(returnedBuilder);

var model = builder.Model;
var index = model.FindEntityType(typeof(Customer)).GetIndexes().Single();
Assert.Equal("[Id] % 2 = 0", index.Relational().Filter);
}

[Fact]
public void Can_set_column_name()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,24 @@ namespace Microsoft.EntityFrameworkCore.Relational.Tests.Metadata
{
public class RelationalMetadataExtensionsTest
{
[Fact]
public void Can_get_and_set_index_filter()
{
var modelBuilder = new ModelBuilder(new ConventionSet());

var property = modelBuilder
.Entity<Customer>()
.HasIndex(e => e.Id)
.HasFilter("[Id] % 2 = 0")
.Metadata;

Assert.Equal("[Id] % 2 = 0", property.Relational().Filter);

property.Relational().Filter = "[Id] % 3 = 0";

Assert.Equal("[Id] % 3 = 0", property.Relational().Filter);
}

[Fact]
public void Can_get_and_set_column_name()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,15 @@ public override void CreateIndexOperation_nonunique()
Sql);
}

public override void CreateIndexOperation_with_where_clauses()
{
base.CreateIndexOperation_with_where_clauses();

Assert.Equal(
"CREATE INDEX \"IX_People_Name\" ON \"People\" (\"Name\") WHERE [Id] > 2;" + EOL,
Sql);
}

public override void CreateSequenceOperation_with_minValue_and_maxValue()
{
base.CreateSequenceOperation_with_minValue_and_maxValue();
Expand Down
Loading