From e967fdad4cd1126a884c897ec0d36b23146086ea Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Wed, 14 Nov 2018 19:31:08 +0100 Subject: [PATCH 1/5] Add support for INCLUDE clause in indexes --- .../Internal/NpgsqlAnnotationCodeGenerator.cs | 2 ++ .../NpgsqlIndexBuilderExtensions.cs | 27 ++++++++++++++++++- .../Metadata/INpgsqlIndexAnnotations.cs | 2 ++ .../Internal/NpgsqlAnnotationNames.cs | 1 + .../Metadata/NpgsqlIndexAnnotations.cs | 11 ++++++++ .../NpgsqlMigrationsAnnotationProvider.cs | 2 ++ .../NpgsqlMigrationsSqlGenerator.cs | 22 ++++++++++----- .../NpgsqlMigrationSqlGeneratorTest.cs | 17 ++++++++++++ 8 files changed, 77 insertions(+), 7 deletions(-) diff --git a/src/EFCore.PG/Design/Internal/NpgsqlAnnotationCodeGenerator.cs b/src/EFCore.PG/Design/Internal/NpgsqlAnnotationCodeGenerator.cs index 6efacd7a2..e34256d3b 100644 --- a/src/EFCore.PG/Design/Internal/NpgsqlAnnotationCodeGenerator.cs +++ b/src/EFCore.PG/Design/Internal/NpgsqlAnnotationCodeGenerator.cs @@ -137,6 +137,8 @@ public override MethodCallCodeFragment GenerateFluentApi(IIndex index, IAnnotati return new MethodCallCodeFragment(nameof(NpgsqlIndexBuilderExtensions.ForNpgsqlHasMethod), annotation.Value); if (annotation.Name == NpgsqlAnnotationNames.IndexOperators) return new MethodCallCodeFragment(nameof(NpgsqlIndexBuilderExtensions.ForNpgsqlHasOperators), annotation.Value); + if (annotation.Name == NpgsqlAnnotationNames.IndexInclude) + return new MethodCallCodeFragment(nameof(NpgsqlIndexBuilderExtensions.ForNpgsqlInclude), annotation.Value); return null; } diff --git a/src/EFCore.PG/Extensions/NpgsqlIndexBuilderExtensions.cs b/src/EFCore.PG/Extensions/NpgsqlIndexBuilderExtensions.cs index 3286fcec3..99cf55687 100644 --- a/src/EFCore.PG/Extensions/NpgsqlIndexBuilderExtensions.cs +++ b/src/EFCore.PG/Extensions/NpgsqlIndexBuilderExtensions.cs @@ -1,4 +1,9 @@ -using JetBrains.Annotations; +using System; +using System.Linq; +using System.Linq.Expressions; +using System.Runtime.CompilerServices; +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata.Builders; using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities; @@ -47,5 +52,25 @@ public static IndexBuilder ForNpgsqlHasOperators([NotNull] this IndexBuilder ind return indexBuilder; } + + public static IndexBuilder ForNpgsqlInclude([NotNull] this IndexBuilder indexBuilder, [CanBeNull] params string[] propertyNames) + { + Check.NotNull(indexBuilder, nameof(indexBuilder)); + Check.NullButNotEmpty(propertyNames, nameof(propertyNames)); + + indexBuilder.Metadata.Npgsql().IncludeProperties = propertyNames; + + return indexBuilder; + } + + public static IndexBuilder ForNpgsqlInclude([NotNull] this IndexBuilder indexBuilder, [NotNull] Expression> includeExpression) + { + Check.NotNull(indexBuilder, nameof(indexBuilder)); + Check.NotNull(includeExpression, nameof(includeExpression)); + + indexBuilder.ForNpgsqlInclude(includeExpression.GetPropertyAccessList().Select(x => x.Name).ToArray()); + + return indexBuilder; + } } } diff --git a/src/EFCore.PG/Metadata/INpgsqlIndexAnnotations.cs b/src/EFCore.PG/Metadata/INpgsqlIndexAnnotations.cs index 2d8011af8..e52260196 100644 --- a/src/EFCore.PG/Metadata/INpgsqlIndexAnnotations.cs +++ b/src/EFCore.PG/Metadata/INpgsqlIndexAnnotations.cs @@ -20,5 +20,7 @@ public interface INpgsqlIndexAnnotations : IRelationalIndexAnnotations /// https://www.postgresql.org/docs/current/static/indexes-opclass.html /// IReadOnlyList Operators { get; } + + IReadOnlyList IncludeProperties { get; } } } diff --git a/src/EFCore.PG/Metadata/Internal/NpgsqlAnnotationNames.cs b/src/EFCore.PG/Metadata/Internal/NpgsqlAnnotationNames.cs index ef2ad788f..7586db565 100644 --- a/src/EFCore.PG/Metadata/Internal/NpgsqlAnnotationNames.cs +++ b/src/EFCore.PG/Metadata/Internal/NpgsqlAnnotationNames.cs @@ -11,6 +11,7 @@ public static class NpgsqlAnnotationNames public const string HiLoSequenceSchema = Prefix + "HiLoSequenceSchema"; public const string IndexMethod = Prefix + "IndexMethod"; public const string IndexOperators = Prefix + "IndexOperators"; + public const string IndexInclude = Prefix + "IndexInclude"; public const string PostgresExtensionPrefix = Prefix + "PostgresExtension:"; public const string EnumPrefix = Prefix + "Enum:"; public const string RangePrefix = Prefix + "Range:"; diff --git a/src/EFCore.PG/Metadata/NpgsqlIndexAnnotations.cs b/src/EFCore.PG/Metadata/NpgsqlIndexAnnotations.cs index 30a52c53e..ed5c666d3 100644 --- a/src/EFCore.PG/Metadata/NpgsqlIndexAnnotations.cs +++ b/src/EFCore.PG/Metadata/NpgsqlIndexAnnotations.cs @@ -43,10 +43,21 @@ public string[] Operators IReadOnlyList INpgsqlIndexAnnotations.Operators => Operators; + public string[] IncludeProperties + { + get => (string[]) Annotations.Metadata[NpgsqlAnnotationNames.IndexInclude]; + set => SetIncludeProperties(value); + } + + IReadOnlyList INpgsqlIndexAnnotations.IncludeProperties => IncludeProperties; + protected virtual bool SetMethod(string value) => Annotations.SetAnnotation(NpgsqlAnnotationNames.IndexMethod, value); protected virtual bool SetOperators(string[] value) => Annotations.SetAnnotation(NpgsqlAnnotationNames.IndexOperators, value); + + protected virtual bool SetIncludeProperties(string[] value) + => Annotations.SetAnnotation(NpgsqlAnnotationNames.IndexInclude, value); } } diff --git a/src/EFCore.PG/Migrations/Internal/NpgsqlMigrationsAnnotationProvider.cs b/src/EFCore.PG/Migrations/Internal/NpgsqlMigrationsAnnotationProvider.cs index 7727f5d50..3998f0613 100644 --- a/src/EFCore.PG/Migrations/Internal/NpgsqlMigrationsAnnotationProvider.cs +++ b/src/EFCore.PG/Migrations/Internal/NpgsqlMigrationsAnnotationProvider.cs @@ -49,6 +49,8 @@ public override IEnumerable For(IIndex index) yield return new Annotation(NpgsqlAnnotationNames.IndexMethod, index.Npgsql().Method); if (index.Npgsql().Operators != null) yield return new Annotation(NpgsqlAnnotationNames.IndexOperators, index.Npgsql().Operators); + if (index.Npgsql().IncludeProperties != null) + yield return new Annotation(NpgsqlAnnotationNames.IndexInclude, index.Npgsql().IncludeProperties); } public override IEnumerable For(IModel model) diff --git a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs index 60ece9273..e7619dee6 100644 --- a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs +++ b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs @@ -563,18 +563,28 @@ protected override void Generate( .Append(IndexColumnList(operation.Columns, operators)) .Append(")"); - if (!string.IsNullOrEmpty(operation.Filter)) - { - builder - .Append(" WHERE ") - .Append(operation.Filter); - } + IndexOptions(operation, model, builder); builder.AppendLine(';'); EndStatement(builder); } + protected override void IndexOptions(CreateIndexOperation operation, IModel model, MigrationCommandListBuilder builder) + { + var includeProperties = (string[])operation[NpgsqlAnnotationNames.IndexInclude]; + + if (includeProperties != null && includeProperties.Length > 0) + { + builder + .Append(" INCLUDE (") + .Append(ColumnList(includeProperties)) + .Append(")"); + } + + base.IndexOptions(operation, model, builder); + } + protected override void Generate(EnsureSchemaOperation operation, [CanBeNull] IModel model, MigrationCommandListBuilder builder) { Check.NotNull(operation, nameof(operation)); diff --git a/test/EFCore.PG.FunctionalTests/NpgsqlMigrationSqlGeneratorTest.cs b/test/EFCore.PG.FunctionalTests/NpgsqlMigrationSqlGeneratorTest.cs index 0126f053e..3809caead 100644 --- a/test/EFCore.PG.FunctionalTests/NpgsqlMigrationSqlGeneratorTest.cs +++ b/test/EFCore.PG.FunctionalTests/NpgsqlMigrationSqlGeneratorTest.cs @@ -633,6 +633,23 @@ public void CreateIndexOperation_operations() Sql); } + [Fact] + public void CreateIndexOperation_includes() + { + Generate( + new CreateIndexOperation + { + Name = "IX_People_Name", + Table = "People", + Columns = new[] { "Name" }, + [NpgsqlAnnotationNames.IndexInclude] = new[] { "FirstName", "LastName" } + }); + + Assert.Equal( + "CREATE INDEX \"IX_People_Name\" ON \"People\" (\"Name\") INCLUDE (\"FirstName\", \"LastName\");" + EOL, + Sql); + } + [Fact] public void CreateIndexOperation_schema_qualified_operations() { From 1da5630ea397b1f8b3a4d0ce7f09a5565e8acc45 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Thu, 15 Nov 2018 19:01:08 +0100 Subject: [PATCH 2/5] Use pattern matching --- .../Migrations/NpgsqlMigrationsSqlGenerator.cs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs index e7619dee6..efef990d2 100644 --- a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs +++ b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs @@ -112,8 +112,7 @@ protected override void Generate( } // Comment on the table - var comment = operation[NpgsqlAnnotationNames.Comment] as string; - if (comment != null) + if (operation[NpgsqlAnnotationNames.Comment] is string comment && comment.Length > 0) { builder.AppendLine(';'); @@ -245,8 +244,7 @@ protected override void Generate( base.Generate(operation, model, builder, terminate: false); - var comment = operation[NpgsqlAnnotationNames.Comment] as string; - if (comment != null) + if (operation[NpgsqlAnnotationNames.Comment] is string comment && comment.Length > 0) { builder.AppendLine(';'); @@ -535,9 +533,6 @@ protected override void Generate( Check.NotNull(operation, nameof(operation)); Check.NotNull(builder, nameof(builder)); - var method = (string)operation[NpgsqlAnnotationNames.IndexMethod]; - var operators = (string[])operation[NpgsqlAnnotationNames.IndexOperators]; - builder.Append("CREATE "); if (operation.IsUnique) @@ -551,13 +546,15 @@ protected override void Generate( .Append(" ON ") .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Table, operation.Schema)); - if (method != null) + if (operation[NpgsqlAnnotationNames.IndexMethod] is string method && method.Length > 0) { builder .Append(" USING ") .Append(method); } + var operators = operation[NpgsqlAnnotationNames.IndexOperators] as string[]; + builder .Append(" (") .Append(IndexColumnList(operation.Columns, operators)) @@ -572,9 +569,7 @@ protected override void Generate( protected override void IndexOptions(CreateIndexOperation operation, IModel model, MigrationCommandListBuilder builder) { - var includeProperties = (string[])operation[NpgsqlAnnotationNames.IndexInclude]; - - if (includeProperties != null && includeProperties.Length > 0) + if (operation[NpgsqlAnnotationNames.IndexInclude] is string[] includeProperties && includeProperties.Length > 0) { builder .Append(" INCLUDE (") From 6eda95c45d8ab0f1bc8b9ac18ea1e23b4062ec24 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Thu, 15 Nov 2018 19:17:53 +0100 Subject: [PATCH 3/5] Add XML docs --- .../NpgsqlIndexBuilderExtensions.cs | 29 +++++++++++++++++++ .../Metadata/INpgsqlIndexAnnotations.cs | 8 ++++- .../Metadata/NpgsqlIndexAnnotations.cs | 8 ++++- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/EFCore.PG/Extensions/NpgsqlIndexBuilderExtensions.cs b/src/EFCore.PG/Extensions/NpgsqlIndexBuilderExtensions.cs index 99cf55687..12fc90b65 100644 --- a/src/EFCore.PG/Extensions/NpgsqlIndexBuilderExtensions.cs +++ b/src/EFCore.PG/Extensions/NpgsqlIndexBuilderExtensions.cs @@ -53,6 +53,16 @@ public static IndexBuilder ForNpgsqlHasOperators([NotNull] this IndexBuilder ind return indexBuilder; } + /// + /// Adds an INCLUDE clause to the index definition with the specified property names. + /// This clause specifies a list of columns which will be included as a non-key part in the index. + /// + /// + /// https://www.postgresql.org/docs/current/sql-createindex.html + /// + /// The builder for the index being configured. + /// An array of property names to be used in INCLUDE clause. + /// A builder to further configure the index. public static IndexBuilder ForNpgsqlInclude([NotNull] this IndexBuilder indexBuilder, [CanBeNull] params string[] propertyNames) { Check.NotNull(indexBuilder, nameof(indexBuilder)); @@ -63,6 +73,25 @@ public static IndexBuilder ForNpgsqlInclude([NotNull] this IndexBuilder indexBui return indexBuilder; } + /// + /// Adds an INCLUDE clause to the index definition with property names from the specified expression. + /// This clause specifies a list of columns which will be included as a non-key part in the index. + /// + /// + /// https://www.postgresql.org/docs/current/sql-createindex.html + /// + /// The builder for the index being configured. + /// + /// + /// A lambda expression representing the property(s) to be included in the INCLUDE clause + /// (blog => blog.Url). + /// + /// + /// If multiple properties are to be included then specify an anonymous type including the + /// properties (post => new { post.Title, post.BlogId }). + /// + /// + /// A builder to further configure the index. public static IndexBuilder ForNpgsqlInclude([NotNull] this IndexBuilder indexBuilder, [NotNull] Expression> includeExpression) { Check.NotNull(indexBuilder, nameof(indexBuilder)); diff --git a/src/EFCore.PG/Metadata/INpgsqlIndexAnnotations.cs b/src/EFCore.PG/Metadata/INpgsqlIndexAnnotations.cs index e52260196..a1565eb02 100644 --- a/src/EFCore.PG/Metadata/INpgsqlIndexAnnotations.cs +++ b/src/EFCore.PG/Metadata/INpgsqlIndexAnnotations.cs @@ -14,13 +14,19 @@ public interface INpgsqlIndexAnnotations : IRelationalIndexAnnotations string Method { get; } /// - /// The PostgreSQL index operators to be used. + /// The PostgreSQL index operators to be used, or null if they have not been specified. /// /// /// https://www.postgresql.org/docs/current/static/indexes-opclass.html /// IReadOnlyList Operators { get; } + /// + /// The PostgreSQL included property names, or null if they have not been specified. + /// + /// + /// https://www.postgresql.org/docs/current/sql-createindex.html + /// IReadOnlyList IncludeProperties { get; } } } diff --git a/src/EFCore.PG/Metadata/NpgsqlIndexAnnotations.cs b/src/EFCore.PG/Metadata/NpgsqlIndexAnnotations.cs index ed5c666d3..a6576ae10 100644 --- a/src/EFCore.PG/Metadata/NpgsqlIndexAnnotations.cs +++ b/src/EFCore.PG/Metadata/NpgsqlIndexAnnotations.cs @@ -30,7 +30,7 @@ public string Method } /// - /// The PostgreSQL index operators to be used. + /// The PostgreSQL index operators to be used, or null if they have not been specified. /// /// /// https://www.postgresql.org/docs/current/static/indexes-opclass.html @@ -43,6 +43,12 @@ public string[] Operators IReadOnlyList INpgsqlIndexAnnotations.Operators => Operators; + /// + /// The PostgreSQL included property names, or null if they have not been specified. + /// + /// + /// https://www.postgresql.org/docs/current/sql-createindex.html + /// public string[] IncludeProperties { get => (string[]) Annotations.Metadata[NpgsqlAnnotationNames.IndexInclude]; From 81ccc5ca6a604d3ccd1390998f5a54e9a35f1403 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Thu, 15 Nov 2018 21:56:48 +0100 Subject: [PATCH 4/5] Add Npgsql-specific method to get generic IndexBuilder --- .../NpgsqlEntityTypeBuilderExtensions.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/EFCore.PG/Extensions/NpgsqlEntityTypeBuilderExtensions.cs b/src/EFCore.PG/Extensions/NpgsqlEntityTypeBuilderExtensions.cs index 1de929bba..04e170de9 100644 --- a/src/EFCore.PG/Extensions/NpgsqlEntityTypeBuilderExtensions.cs +++ b/src/EFCore.PG/Extensions/NpgsqlEntityTypeBuilderExtensions.cs @@ -1,7 +1,11 @@ using System; using System.Collections.Generic; +using System.Linq.Expressions; using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.EntityFrameworkCore.Metadata.Internal; using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities; // ReSharper disable once CheckNamespace @@ -136,5 +140,39 @@ public static EntityTypeBuilder ForCockroachDbInterleaveInParent (EntityTypeBuilder)ForCockroachDbInterleaveInParent((EntityTypeBuilder)entityTypeBuilder, parentTableType, interleavePrefix); #endregion CockroachDB Interleave-in-parent + + #region Generic Index + + /// + /// Configures an index on the specified properties. If there is an existing index on the given + /// set of properties, then the existing index will be returned for configuration. + /// + /// The entity type being configured. + /// The builder for the entity type being configured. + /// + /// + /// A lambda expression representing the property(s) to be included in the index + /// (blog => blog.Url). + /// + /// + /// If the index is made up of multiple properties then specify an anonymous type including the + /// properties (post => new { post.Title, post.BlogId }). + /// + /// + /// An object that can be used to configure the index. + public static IndexBuilder ForNpgsqlHasIndex( + [NotNull] this EntityTypeBuilder entityTypeBuilder, [NotNull] Expression> indexExpression) + where TEntity : class + { + Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); + Check.NotNull(indexExpression, nameof(indexExpression)); + + var builder = ((IInfrastructure)entityTypeBuilder).GetInfrastructure(); + + return new IndexBuilder( + builder.HasIndex(indexExpression.GetPropertyAccessList(), ConfigurationSource.Explicit)); + } + + #endregion } } From 53bdc8caf0e71758abd721c33910519b919217da Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Thu, 15 Nov 2018 22:41:26 +0100 Subject: [PATCH 5/5] Address PR feedback --- .../NpgsqlEntityTypeBuilderExtensions.cs | 23 ++++++++++--------- .../NpgsqlIndexBuilderExtensions.cs | 16 +++++++++---- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/EFCore.PG/Extensions/NpgsqlEntityTypeBuilderExtensions.cs b/src/EFCore.PG/Extensions/NpgsqlEntityTypeBuilderExtensions.cs index 04e170de9..8fa610eba 100644 --- a/src/EFCore.PG/Extensions/NpgsqlEntityTypeBuilderExtensions.cs +++ b/src/EFCore.PG/Extensions/NpgsqlEntityTypeBuilderExtensions.cs @@ -144,24 +144,25 @@ public static EntityTypeBuilder ForCockroachDbInterleaveInParent - /// Configures an index on the specified properties. If there is an existing index on the given - /// set of properties, then the existing index will be returned for configuration. + /// Configures an index on the specified properties. If there is an existing index on the given + /// set of properties, then the existing index will be returned for configuration. /// /// The entity type being configured. /// The builder for the entity type being configured. /// - /// - /// A lambda expression representing the property(s) to be included in the index - /// (blog => blog.Url). - /// - /// - /// If the index is made up of multiple properties then specify an anonymous type including the - /// properties (post => new { post.Title, post.BlogId }). - /// + /// + /// A lambda expression representing the property(s) to be included in the index + /// (blog => blog.Url). + /// + /// + /// If the index is made up of multiple properties then specify an anonymous type including the + /// properties (post => new { post.Title, post.BlogId }). + /// /// /// An object that can be used to configure the index. public static IndexBuilder ForNpgsqlHasIndex( - [NotNull] this EntityTypeBuilder entityTypeBuilder, [NotNull] Expression> indexExpression) + [NotNull] this EntityTypeBuilder entityTypeBuilder, + [NotNull] Expression> indexExpression) where TEntity : class { Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); diff --git a/src/EFCore.PG/Extensions/NpgsqlIndexBuilderExtensions.cs b/src/EFCore.PG/Extensions/NpgsqlIndexBuilderExtensions.cs index 12fc90b65..146c25f79 100644 --- a/src/EFCore.PG/Extensions/NpgsqlIndexBuilderExtensions.cs +++ b/src/EFCore.PG/Extensions/NpgsqlIndexBuilderExtensions.cs @@ -24,7 +24,9 @@ public static class NpgsqlIndexBuilderExtensions /// The builder for the index being configured. /// The name of the index. /// A builder to further configure the index. - public static IndexBuilder ForNpgsqlHasMethod([NotNull] this IndexBuilder indexBuilder, [CanBeNull] string method) + public static IndexBuilder ForNpgsqlHasMethod( + [NotNull] this IndexBuilder indexBuilder, + [CanBeNull] string method) { Check.NotNull(indexBuilder, nameof(indexBuilder)); Check.NullButNotEmpty(method, nameof(method)); @@ -43,7 +45,9 @@ public static IndexBuilder ForNpgsqlHasMethod([NotNull] this IndexBuilder indexB /// The builder for the index being configured. /// The operators to use for each column. /// A builder to further configure the index. - public static IndexBuilder ForNpgsqlHasOperators([NotNull] this IndexBuilder indexBuilder, [CanBeNull] params string[] operators) + public static IndexBuilder ForNpgsqlHasOperators( + [NotNull] this IndexBuilder indexBuilder, + [CanBeNull, ItemNotNull] params string[] operators) { Check.NotNull(indexBuilder, nameof(indexBuilder)); Check.NullButNotEmpty(operators, nameof(operators)); @@ -63,7 +67,9 @@ public static IndexBuilder ForNpgsqlHasOperators([NotNull] this IndexBuilder ind /// The builder for the index being configured. /// An array of property names to be used in INCLUDE clause. /// A builder to further configure the index. - public static IndexBuilder ForNpgsqlInclude([NotNull] this IndexBuilder indexBuilder, [CanBeNull] params string[] propertyNames) + public static IndexBuilder ForNpgsqlInclude( + [NotNull] this IndexBuilder indexBuilder, + [CanBeNull, ItemNotNull] params string[] propertyNames) { Check.NotNull(indexBuilder, nameof(indexBuilder)); Check.NullButNotEmpty(propertyNames, nameof(propertyNames)); @@ -92,7 +98,9 @@ public static IndexBuilder ForNpgsqlInclude([NotNull] this IndexBuilder indexBui /// /// /// A builder to further configure the index. - public static IndexBuilder ForNpgsqlInclude([NotNull] this IndexBuilder indexBuilder, [NotNull] Expression> includeExpression) + public static IndexBuilder ForNpgsqlInclude( + [NotNull] this IndexBuilder indexBuilder, + [NotNull] Expression> includeExpression) { Check.NotNull(indexBuilder, nameof(indexBuilder)); Check.NotNull(includeExpression, nameof(includeExpression));