Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
jobily
Efcore.Pg
提交
08d8cc55
E
Efcore.Pg
项目概览
jobily
/
Efcore.Pg
11 个月 前同步成功
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
E
Efcore.Pg
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
08d8cc55
编写于
2月 11, 2022
作者:
S
Shay Rojansky
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Support new EF Core way for specifying descending indexes
Closes #2267
上级
a6017db2
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
279 addition
and
228 deletion
+279
-228
src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlIndexBuilderExtensions.cs
...ensions/BuilderExtensions/NpgsqlIndexBuilderExtensions.cs
+107
-99
src/EFCore.PG/Extensions/MetadataExtensions/NpgsqlIndexExtensions.cs
...PG/Extensions/MetadataExtensions/NpgsqlIndexExtensions.cs
+52
-48
src/EFCore.PG/Metadata/Internal/NpgsqlAnnotationNames.cs
src/EFCore.PG/Metadata/Internal/NpgsqlAnnotationNames.cs
+3
-1
src/EFCore.PG/Metadata/Internal/NpgsqlAnnotationProvider.cs
src/EFCore.PG/Metadata/Internal/NpgsqlAnnotationProvider.cs
+6
-5
src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs
src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs
+13
-7
src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs
...ore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs
+7
-17
src/EFCore.PG/Utilities/SortOrderHelper.cs
src/EFCore.PG/Utilities/SortOrderHelper.cs
+2
-7
test/EFCore.PG.FunctionalTests/Migrations/MigrationsNpgsqlTest.cs
...ore.PG.FunctionalTests/Migrations/MigrationsNpgsqlTest.cs
+79
-35
test/EFCore.PG.FunctionalTests/Scaffolding/NpgsqlDatabaseModelFactoryTest.cs
...tionalTests/Scaffolding/NpgsqlDatabaseModelFactoryTest.cs
+10
-9
未找到文件。
src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlIndexBuilderExtensions.cs
浏览文件 @
08d8cc55
...
...
@@ -369,99 +369,6 @@ public static class NpgsqlIndexBuilderExtensions
#
endregion
Collation
#
region
Sort
order
/// <summary>
/// The PostgreSQL index sort ordering to be used.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
/// <param name="indexBuilder">The builder for the index being configured.</param>
/// <param name="values">The sort order to use for each column.</param>
/// <returns>A builder to further configure the index.</returns>
public
static
IndexBuilder
HasSortOrder
(
this
IndexBuilder
indexBuilder
,
params
SortOrder
[]?
values
)
{
Check
.
NotNull
(
indexBuilder
,
nameof
(
indexBuilder
));
Check
.
NullButNotEmpty
(
values
,
nameof
(
values
));
if
(!
SortOrderHelper
.
IsDefaultSortOrder
(
values
))
{
indexBuilder
.
Metadata
.
SetSortOrder
(
values
);
}
return
indexBuilder
;
}
/// <summary>
/// The PostgreSQL index sort ordering to be used.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
/// <param name="indexBuilder">The builder for the index being configured.</param>
/// <param name="values">The sort order to use for each column.</param>
/// <returns>A builder to further configure the index.</returns>
public
static
IndexBuilder
<
TEntity
>
HasSortOrder
<
TEntity
>(
this
IndexBuilder
<
TEntity
>
indexBuilder
,
params
SortOrder
[]?
values
)
=>
(
IndexBuilder
<
TEntity
>)
HasSortOrder
((
IndexBuilder
)
indexBuilder
,
values
);
/// <summary>
/// The PostgreSQL index sort ordering to be used.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
/// <param name="indexBuilder">The builder for the index being configured.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <param name="values">The sort order to use for each column.</param>
/// <returns>A builder to further configure the index.</returns>
public
static
IConventionIndexBuilder
?
HasSortOrder
(
this
IConventionIndexBuilder
indexBuilder
,
IReadOnlyList
<
SortOrder
>?
values
,
bool
fromDataAnnotation
)
{
if
(
indexBuilder
.
CanSetSortOrder
(
values
,
fromDataAnnotation
))
{
Check
.
NotNull
(
indexBuilder
,
nameof
(
indexBuilder
));
Check
.
NullButNotEmpty
(
values
,
nameof
(
values
));
if
(!
SortOrderHelper
.
IsDefaultSortOrder
(
values
))
{
indexBuilder
.
Metadata
.
SetSortOrder
(
values
,
fromDataAnnotation
);
}
return
indexBuilder
;
}
return
null
;
}
/// <summary>
/// Returns a value indicating whether the PostgreSQL index sort ordering can be set.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
/// <param name="indexBuilder">The builder for the index being configured.</param>
/// <param name="values">The sort order to use for each column.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns>A builder to further configure the index.</returns>
public
static
bool
CanSetSortOrder
(
this
IConventionIndexBuilder
indexBuilder
,
IReadOnlyList
<
SortOrder
>?
values
,
bool
fromDataAnnotation
)
{
Check
.
NotNull
(
indexBuilder
,
nameof
(
indexBuilder
));
return
indexBuilder
.
CanSetAnnotation
(
NpgsqlAnnotationNames
.
IndexSortOrder
,
values
,
fromDataAnnotation
);
}
#
endregion
Sort
order
#
region
Null
sort
order
/// <summary>
...
...
@@ -480,9 +387,7 @@ public static class NpgsqlIndexBuilderExtensions
Check
.
NotNull
(
indexBuilder
,
nameof
(
indexBuilder
));
Check
.
NullButNotEmpty
(
values
,
nameof
(
values
));
var
sortOrders
=
indexBuilder
.
Metadata
.
GetSortOrder
();
if
(!
SortOrderHelper
.
IsDefaultNullSortOrder
(
values
,
sortOrders
))
if
(!
SortOrderHelper
.
IsDefaultNullSortOrder
(
values
,
indexBuilder
.
Metadata
.
IsDescending
))
{
indexBuilder
.
Metadata
.
SetNullSortOrder
(
values
);
}
...
...
@@ -521,9 +426,7 @@ public static class NpgsqlIndexBuilderExtensions
{
if
(
indexBuilder
.
CanSetNullSortOrder
(
values
,
fromDataAnnotation
))
{
var
sortOrders
=
indexBuilder
.
Metadata
.
GetSortOrder
();
if
(!
SortOrderHelper
.
IsDefaultNullSortOrder
(
values
,
sortOrders
))
if
(!
SortOrderHelper
.
IsDefaultNullSortOrder
(
values
,
indexBuilder
.
Metadata
.
IsDescending
))
{
indexBuilder
.
Metadata
.
SetNullSortOrder
(
values
,
fromDataAnnotation
);
}
...
...
@@ -763,6 +666,111 @@ public static IndexBuilder<TEntity> IsCreatedConcurrently<TEntity>(this IndexBui
#
endregion
Created
concurrently
#
region
Sort
order
(
legacy
)
/// <summary>
/// The PostgreSQL index sort ordering to be used.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
/// <param name="indexBuilder">The builder for the index being configured.</param>
/// <param name="values">The sort order to use for each column.</param>
/// <returns>A builder to further configure the index.</returns>
[
Obsolete
(
"Use IsDescending instead"
)]
public
static
IndexBuilder
HasSortOrder
(
this
IndexBuilder
indexBuilder
,
params
SortOrder
[]?
values
)
{
Check
.
NotNull
(
indexBuilder
,
nameof
(
indexBuilder
));
Check
.
NullButNotEmpty
(
values
,
nameof
(
values
));
var
isDescending
=
new
bool
[
indexBuilder
.
Metadata
.
Properties
.
Count
];
for
(
var
i
=
0
;
i
<
isDescending
.
Length
;
i
++)
{
isDescending
[
i
]
=
values
?.
Length
>
i
&&
values
[
i
]
==
SortOrder
.
Descending
;
}
indexBuilder
.
IsDescending
(
isDescending
);
return
indexBuilder
;
}
/// <summary>
/// The PostgreSQL index sort ordering to be used.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
/// <param name="indexBuilder">The builder for the index being configured.</param>
/// <param name="values">The sort order to use for each column.</param>
/// <returns>A builder to further configure the index.</returns>
[
Obsolete
(
"Use IsDescending instead"
)]
public
static
IndexBuilder
<
TEntity
>
HasSortOrder
<
TEntity
>(
this
IndexBuilder
<
TEntity
>
indexBuilder
,
params
SortOrder
[]?
values
)
=>
(
IndexBuilder
<
TEntity
>)
HasSortOrder
((
IndexBuilder
)
indexBuilder
,
values
);
/// <summary>
/// The PostgreSQL index sort ordering to be used.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
/// <param name="indexBuilder">The builder for the index being configured.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <param name="values">The sort order to use for each column.</param>
/// <returns>A builder to further configure the index.</returns>
[
Obsolete
(
"Use IsDescending instead"
)]
public
static
IConventionIndexBuilder
?
HasSortOrder
(
this
IConventionIndexBuilder
indexBuilder
,
IReadOnlyList
<
SortOrder
>?
values
,
bool
fromDataAnnotation
)
{
if
(
indexBuilder
.
CanSetSortOrder
(
values
,
fromDataAnnotation
))
{
Check
.
NotNull
(
indexBuilder
,
nameof
(
indexBuilder
));
Check
.
NullButNotEmpty
(
values
,
nameof
(
values
));
var
isDescending
=
new
bool
[
indexBuilder
.
Metadata
.
Properties
.
Count
];
for
(
var
i
=
0
;
i
<
isDescending
.
Length
;
i
++)
{
isDescending
[
i
]
=
values
?.
Count
>
i
&&
values
[
i
]
==
SortOrder
.
Descending
;
}
indexBuilder
.
IsDescending
(
isDescending
);
return
indexBuilder
;
}
return
null
;
}
/// <summary>
/// Returns a value indicating whether the PostgreSQL index sort ordering can be set.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
/// <param name="indexBuilder">The builder for the index being configured.</param>
/// <param name="values">The sort order to use for each column.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns>A builder to further configure the index.</returns>
[
Obsolete
(
"Use IsDescending instead"
)]
public
static
bool
CanSetSortOrder
(
this
IConventionIndexBuilder
indexBuilder
,
IReadOnlyList
<
SortOrder
>?
values
,
bool
fromDataAnnotation
)
{
Check
.
NotNull
(
indexBuilder
,
nameof
(
indexBuilder
));
return
indexBuilder
.
CanSetAnnotation
(
NpgsqlAnnotationNames
.
IndexSortOrder
,
values
,
fromDataAnnotation
);
}
#
endregion
Sort
order
(
obsolete
)
#
region
Obsolete
/// <summary>
...
...
src/EFCore.PG/Extensions/MetadataExtensions/NpgsqlIndexExtensions.cs
浏览文件 @
08d8cc55
...
...
@@ -159,54 +159,6 @@ public static void SetCollation(this IMutableIndex index, IReadOnlyList<string>?
#
endregion
Collation
#
region
Sort
order
/// <summary>
/// Returns the column sort orders to be used, or <c>null</c> if they have not been specified.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
public
static
IReadOnlyList
<
SortOrder
>?
GetSortOrder
(
this
IReadOnlyIndex
index
)
=>
(
IReadOnlyList
<
SortOrder
>?)
index
[
NpgsqlAnnotationNames
.
IndexSortOrder
];
/// <summary>
/// Sets the column sort orders to be used, or <c>null</c> if they have not been specified.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
public
static
void
SetSortOrder
(
this
IMutableIndex
index
,
IReadOnlyList
<
SortOrder
>?
sortOrder
)
=>
index
.
SetOrRemoveAnnotation
(
NpgsqlAnnotationNames
.
IndexSortOrder
,
sortOrder
);
/// <summary>
/// Sets the column sort orders to be used, or <c>null</c> if they have not been specified.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
public
static
IReadOnlyList
<
SortOrder
>?
SetSortOrder
(
this
IConventionIndex
index
,
IReadOnlyList
<
SortOrder
>?
sortOrder
,
bool
fromDataAnnotation
=
false
)
{
Check
.
NullButNotEmpty
(
sortOrder
,
nameof
(
sortOrder
));
index
.
SetOrRemoveAnnotation
(
NpgsqlAnnotationNames
.
IndexSortOrder
,
sortOrder
,
fromDataAnnotation
);
return
sortOrder
;
}
/// <summary>
/// Returns the <see cref="ConfigurationSource" /> for the index sort orders.
/// </summary>
/// <param name="index">The index.</param>
/// <returns>The <see cref="ConfigurationSource" /> for the index sort orders.</returns>
public
static
ConfigurationSource
?
GetSortOrderConfigurationSource
(
this
IConventionIndex
index
)
=>
index
.
FindAnnotation
(
NpgsqlAnnotationNames
.
IndexSortOrder
)?.
GetConfigurationSource
();
#
endregion
Sort
order
#
region
Null
sort
order
/// <summary>
...
...
@@ -419,4 +371,56 @@ public static void SetTsVectorConfig(this IMutableIndex index, string? config)
=>
index
.
FindAnnotation
(
NpgsqlAnnotationNames
.
TsVectorConfig
)?.
GetConfigurationSource
();
#
endregion
ToTsVector
#
region
Sort
order
(
legacy
)
/// <summary>
/// Returns the column sort orders to be used, or <c>null</c> if they have not been specified.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
[
Obsolete
(
"Use IsDescending instead"
)]
public
static
IReadOnlyList
<
SortOrder
>?
GetSortOrder
(
this
IReadOnlyIndex
index
)
=>
(
IReadOnlyList
<
SortOrder
>?)
index
[
NpgsqlAnnotationNames
.
IndexSortOrder
];
/// <summary>
/// Sets the column sort orders to be used, or <c>null</c> if they have not been specified.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
[
Obsolete
(
"Use IsDescending instead"
)]
public
static
void
SetSortOrder
(
this
IMutableIndex
index
,
IReadOnlyList
<
SortOrder
>?
sortOrder
)
=>
index
.
SetOrRemoveAnnotation
(
NpgsqlAnnotationNames
.
IndexSortOrder
,
sortOrder
);
/// <summary>
/// Sets the column sort orders to be used, or <c>null</c> if they have not been specified.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
[
Obsolete
(
"Use IsDescending instead"
)]
public
static
IReadOnlyList
<
SortOrder
>?
SetSortOrder
(
this
IConventionIndex
index
,
IReadOnlyList
<
SortOrder
>?
sortOrder
,
bool
fromDataAnnotation
=
false
)
{
Check
.
NullButNotEmpty
(
sortOrder
,
nameof
(
sortOrder
));
index
.
SetOrRemoveAnnotation
(
NpgsqlAnnotationNames
.
IndexSortOrder
,
sortOrder
,
fromDataAnnotation
);
return
sortOrder
;
}
/// <summary>
/// Returns the <see cref="ConfigurationSource" /> for the index sort orders.
/// </summary>
/// <param name="index">The index.</param>
/// <returns>The <see cref="ConfigurationSource" /> for the index sort orders.</returns>
[
Obsolete
(
"Use IsDescending instead"
)]
public
static
ConfigurationSource
?
GetSortOrderConfigurationSource
(
this
IConventionIndex
index
)
=>
index
.
FindAnnotation
(
NpgsqlAnnotationNames
.
IndexSortOrder
)?.
GetConfigurationSource
();
#
endregion
Sort
order
(
legacy
)
}
\ No newline at end of file
src/EFCore.PG/Metadata/Internal/NpgsqlAnnotationNames.cs
浏览文件 @
08d8cc55
...
...
@@ -13,7 +13,6 @@ public static class NpgsqlAnnotationNames
public
const
string
IdentityOptions
=
Prefix
+
"IdentitySequenceOptions"
;
public
const
string
IndexMethod
=
Prefix
+
"IndexMethod"
;
public
const
string
IndexOperators
=
Prefix
+
"IndexOperators"
;
public
const
string
IndexSortOrder
=
Prefix
+
"IndexSortOrder"
;
public
const
string
IndexNullSortOrder
=
Prefix
+
"IndexNullSortOrder"
;
public
const
string
IndexInclude
=
Prefix
+
"IndexInclude"
;
public
const
string
Tablespace
=
Prefix
+
"Tablespace"
;
...
...
@@ -55,4 +54,7 @@ public static class NpgsqlAnnotationNames
[
Obsolete
(
"Replaced by RelationalAnnotationNames.Collation"
)]
public
const
string
IndexCollation
=
Prefix
+
"IndexCollation"
;
// Replaced by IsDescending in EF Core 7.0
public
const
string
IndexSortOrder
=
Prefix
+
"IndexSortOrder"
;
}
\ No newline at end of file
src/EFCore.PG/Metadata/Internal/NpgsqlAnnotationProvider.cs
浏览文件 @
08d8cc55
...
...
@@ -133,11 +133,6 @@ public override IEnumerable<IAnnotation> For(ITableIndex index, bool designTime)
yield
return
new
Annotation
(
NpgsqlAnnotationNames
.
IndexOperators
,
operators
);
}
if
(
modelIndex
.
GetSortOrder
()
is
{
}
sortOrder
)
{
yield
return
new
Annotation
(
NpgsqlAnnotationNames
.
IndexSortOrder
,
sortOrder
);
}
if
(
modelIndex
.
GetNullSortOrder
()
is
{
}
nullSortOrder
)
{
yield
return
new
Annotation
(
NpgsqlAnnotationNames
.
IndexNullSortOrder
,
nullSortOrder
);
...
...
@@ -166,6 +161,12 @@ public override IEnumerable<IAnnotation> For(ITableIndex index, bool designTime)
NpgsqlAnnotationNames
.
CreatedConcurrently
,
isCreatedConcurrently
.
Value
);
}
// Support legacy annotation for index ordering
if
(
modelIndex
[
NpgsqlAnnotationNames
.
IndexSortOrder
]
is
IReadOnlyList
<
SortOrder
>
legacySortOrder
)
{
yield
return
new
Annotation
(
NpgsqlAnnotationNames
.
IndexSortOrder
,
legacySortOrder
);
}
}
public
override
IEnumerable
<
IAnnotation
>
For
(
IRelationalModel
model
,
bool
designTime
)
...
...
src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs
浏览文件 @
08d8cc55
...
...
@@ -1940,7 +1940,7 @@ private string IndexColumnList(IndexColumn[] columns, string? method)
// sorting, thus we only want to emit sort options for btree indexes.
if
(
method
is
null
||
method
==
"btree"
)
{
if
(
column
.
SortOrder
==
SortOrder
.
Descending
)
if
(
column
.
Is
Descending
)
{
builder
.
Append
(
" DESC"
);
}
...
...
@@ -2006,7 +2006,11 @@ private static IndexColumn[] GetIndexColumns(CreateIndexOperation operation)
var
collations
=
operation
[
RelationalAnnotationNames
.
Collation
]
as
string
[];
var
operators
=
operation
[
NpgsqlAnnotationNames
.
IndexOperators
]
as
string
[];
var
sortOrders
=
operation
[
NpgsqlAnnotationNames
.
IndexSortOrder
]
as
SortOrder
[];
// We used to have our own annotation-based descending index mechanism, this got replaced with IsDescending in EF Core 7.0.
var
isDescendingValues
=
operation
.
IsDescending
;
var
legacySortOrders
=
operation
[
NpgsqlAnnotationNames
.
IndexSortOrder
]
as
SortOrder
[];
var
nullSortOrders
=
operation
[
NpgsqlAnnotationNames
.
IndexNullSortOrder
]
as
NullSortOrder
[];
var
columns
=
new
IndexColumn
[
operation
.
Columns
.
Length
];
...
...
@@ -2016,10 +2020,12 @@ private static IndexColumn[] GetIndexColumns(CreateIndexOperation operation)
var
name
=
operation
.
Columns
[
i
];
var
@operator
=
i
<
operators
?.
Length
?
operators
[
i
]
:
null
;
var
collation
=
i
<
collations
?.
Length
?
collations
[
i
]
:
null
;
var
sortOrder
=
i
<
sortOrders
?.
Length
?
sortOrders
[
i
]
:
SortOrder
.
Ascending
;
var
isColumnDescending
=
isDescendingValues
is
not
null
?
isDescendingValues
[
i
]
:
i
<
legacySortOrders
?.
Length
&&
legacySortOrders
[
i
]
==
SortOrder
.
Descending
;
var
nullSortOrder
=
i
<
nullSortOrders
?.
Length
?
nullSortOrders
[
i
]
:
NullSortOrder
.
Unspecified
;
columns
[
i
]
=
new
IndexColumn
(
name
,
@operator
,
collation
,
sortOrder
,
nullSortOrder
);
columns
[
i
]
=
new
IndexColumn
(
name
,
@operator
,
collation
,
isColumnDescending
,
nullSortOrder
);
}
return
columns
;
...
...
@@ -2027,19 +2033,19 @@ private static IndexColumn[] GetIndexColumns(CreateIndexOperation operation)
private
readonly
struct
IndexColumn
{
public
IndexColumn
(
string
name
,
string
?
@operator
,
string
?
collation
,
SortOrder
sortOrder
,
NullSortOrder
nullSortOrder
)
public
IndexColumn
(
string
name
,
string
?
@operator
,
string
?
collation
,
bool
isDescending
,
NullSortOrder
nullSortOrder
)
{
Name
=
name
;
Operator
=
@operator
;
Collation
=
collation
;
SortOrder
=
sortOrder
;
IsDescending
=
isDescending
;
NullSortOrder
=
nullSortOrder
;
}
public
string
Name
{
get
;
}
public
string
?
Operator
{
get
;
}
public
string
?
Collation
{
get
;
}
public
SortOrder
SortOrder
{
get
;
}
public
bool
IsDescending
{
get
;
}
public
NullSortOrder
NullSortOrder
{
get
;
}
}
...
...
src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs
浏览文件 @
08d8cc55
...
...
@@ -710,26 +710,16 @@ deptype IN ('e', 'x')
{
var
options
=
record
.
GetFieldValue
<
ushort
[
]>
(
"indoption"
);
// The first bit specifies whether values are sorted in descending order.
const
ushort
indoptionDescFlag
=
0x0001
;
var
sortOrders
=
options
.
Select
(
val
=>
(
val
&
indoptionDescFlag
)
!=
0
?
SortOrder
.
Descending
:
SortOrder
.
Ascending
)
.
ToArray
();
if
(!
SortOrderHelper
.
IsDefaultSortOrder
(
sortOrders
))
{
index
[
NpgsqlAnnotationNames
.
IndexSortOrder
]
=
sortOrders
;
}
// The second bit specifies whether NULLs are sorted first instead of last.
const
ushort
indoptionNullsFirstFlag
=
0x0002
;
// The first bit in indoption specifies whether values are sorted in descending order, the second whether
// NULLs are sorted first instead of last.
var
isDescending
=
options
.
Select
(
val
=>
(
val
&
0x0001
)
!=
0
).
ToList
();
var
nullSortOrders
=
options
.
Select
(
val
=>
(
val
&
indoptionNullsFirstFlag
)
!=
0
?
NullSortOrder
.
NullsFirst
:
NullSortOrder
.
NullsLast
)
.
Select
(
val
=>
(
val
&
0x0002
)
!=
0
?
NullSortOrder
.
NullsFirst
:
NullSortOrder
.
NullsLast
)
.
ToArray
();
if
(!
SortOrderHelper
.
IsDefaultNullSortOrder
(
nullSortOrders
,
sortOrders
))
index
.
IsDescending
=
isDescending
;
if
(!
SortOrderHelper
.
IsDefaultNullSortOrder
(
nullSortOrders
,
isDescending
))
{
index
[
NpgsqlAnnotationNames
.
IndexNullSortOrder
]
=
nullSortOrders
;
}
...
...
src/EFCore.PG/Utilities/SortOrderHelper.cs
浏览文件 @
08d8cc55
...
...
@@ -4,12 +4,9 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Utilities;
internal
static
class
SortOrderHelper
{
public
static
bool
IsDefaultSortOrder
(
IReadOnlyList
<
SortOrder
>?
sortOrders
)
=>
sortOrders
?.
All
(
sortOrder
=>
sortOrder
==
SortOrder
.
Ascending
)
??
true
;
public
static
bool
IsDefaultNullSortOrder
(
IReadOnlyList
<
NullSortOrder
>?
nullSortOrders
,
IReadOnlyList
<
SortOrder
>?
sortOrder
s
)
IReadOnlyList
<
bool
>?
isDescendingValue
s
)
{
if
(
nullSortOrders
is
null
)
{
...
...
@@ -21,9 +18,7 @@ public static bool IsDefaultSortOrder(IReadOnlyList<SortOrder>? sortOrders)
var
nullSortOrder
=
nullSortOrders
[
i
];
// We need to consider the ASC/DESC sort order to determine the default NULLS FIRST/LAST sort order.
var
sortOrder
=
i
<
sortOrders
?.
Count
?
sortOrders
[
i
]
:
SortOrder
.
Ascending
;
if
(
sortOrder
==
SortOrder
.
Descending
)
if
(
isDescendingValues
is
not
null
&&
isDescendingValues
[
i
])
{
// NULLS FIRST is the default when DESC is specified.
if
(
nullSortOrder
!=
NullSortOrder
.
NullsFirst
)
...
...
test/EFCore.PG.FunctionalTests/Migrations/MigrationsNpgsqlTest.cs
浏览文件 @
08d8cc55
...
...
@@ -1817,13 +1817,77 @@ public override async Task Create_index_unique()
@"CREATE UNIQUE INDEX ""IX_People_FirstName_LastName"" ON ""People"" (""FirstName"", ""LastName"");"
);
}
[
ConditionalFact
(
Skip
=
"https://github.com/npgsql/efcore.pg/issues/2267"
)]
public
override
Task
Create_index_descending
()
=>
Task
.
CompletedTask
;
public
override
async
Task
Create_index_descending
()
{
await
base
.
Create_index_descending
();
AssertSql
(
@"CREATE INDEX ""IX_People_X"" ON ""People"" (""X"" DESC);"
);
}
public
override
async
Task
Create_index_descending_mixed
()
{
await
base
.
Create_index_descending_mixed
();
AssertSql
(
@"CREATE INDEX ""IX_People_X_Y_Z"" ON ""People"" (""X"", ""Y"" DESC, ""Z"");"
);
}
#pragma warning disable CS0618 // HasSortOrder is obsolete
[
Fact
]
public
virtual
async
Task
Create_index_descending_mixed_legacy_api
()
{
await
Test
(
builder
=>
builder
.
Entity
(
"People"
,
e
=>
{
e
.
Property
<
int
>(
"Id"
);
e
.
Property
<
int
>(
"X"
);
e
.
Property
<
int
>(
"Y"
);
e
.
Property
<
int
>(
"Z"
);
}),
builder
=>
{
},
builder
=>
builder
.
Entity
(
"People"
)
.
HasIndex
(
"X"
,
"Y"
,
"Z"
)
.
HasSortOrder
(
SortOrder
.
Ascending
,
SortOrder
.
Descending
),
model
=>
{
var
table
=
Assert
.
Single
(
model
.
Tables
);
var
index
=
Assert
.
Single
(
table
.
Indexes
);
Assert
.
Collection
(
index
.
IsDescending
,
Assert
.
False
,
Assert
.
True
,
Assert
.
False
);
});
AssertSql
(
@"CREATE INDEX ""IX_People_X_Y_Z"" ON ""People"" (""X"", ""Y"" DESC, ""Z"");"
);
}
#pragma warning restore CS0618
[
Fact
]
public
virtual
async
Task
Create_index_descending_mixed_legacy_annotation
()
{
await
Test
(
builder
=>
builder
.
Entity
(
"People"
,
e
=>
{
e
.
Property
<
int
>(
"Id"
);
e
.
Property
<
int
>(
"X"
);
e
.
Property
<
int
>(
"Y"
);
e
.
Property
<
int
>(
"Z"
);
}),
builder
=>
{
},
builder
=>
builder
.
Entity
(
"People"
)
.
HasIndex
(
"X"
,
"Y"
,
"Z"
)
.
HasAnnotation
(
NpgsqlAnnotationNames
.
IndexSortOrder
,
new
[]
{
SortOrder
.
Ascending
,
SortOrder
.
Descending
}),
model
=>
{
var
table
=
Assert
.
Single
(
model
.
Tables
);
var
index
=
Assert
.
Single
(
table
.
Indexes
);
Assert
.
Collection
(
index
.
IsDescending
,
Assert
.
False
,
Assert
.
True
,
Assert
.
False
);
});
[
ConditionalFact
(
Skip
=
"https://github.com/npgsql/efcore.pg/issues/2267"
)]
public
override
Task
Create_index_descending_mixed
()
=>
Task
.
CompletedTask
;
AssertSql
(
@"CREATE INDEX ""IX_People_X_Y_Z"" ON ""People"" (""X"", ""Y"" DESC, ""Z"");"
);
}
public
override
async
Task
Create_index_with_filter
()
{
...
...
@@ -2089,32 +2153,6 @@ public virtual async Task Create_index_with_operators()
// so we test support for this on the generated SQL only, in NpgsqlMigrationSqlGeneratorTest, and not against
// the database here.
[
Fact
]
public
virtual
async
Task
Create_index_with_sort_order
()
{
await
Test
(
builder
=>
builder
.
Entity
(
"People"
,
e
=>
{
e
.
Property
<
int
>(
"Id"
);
e
.
Property
<
string
>(
"FirstName"
);
e
.
Property
<
string
>(
"LastName"
);
}),
_
=>
{
},
builder
=>
builder
.
Entity
(
"People"
).
HasIndex
(
"FirstName"
,
"LastName"
)
.
HasSortOrder
(
SortOrder
.
Descending
,
SortOrder
.
Ascending
),
model
=>
{
var
table
=
Assert
.
Single
(
model
.
Tables
);
var
index
=
Assert
.
Single
(
table
.
Indexes
);
Assert
.
Equal
(
new
[]
{
SortOrder
.
Descending
,
SortOrder
.
Ascending
},
index
[
NpgsqlAnnotationNames
.
IndexSortOrder
]);
});
AssertSql
(
@"CREATE INDEX ""IX_People_FirstName_LastName"" ON ""People"" (""FirstName"" DESC, ""LastName"");"
);
}
[
Fact
]
public
virtual
async
Task
Create_index_with_null_sort_order
()
{
...
...
@@ -2183,9 +2221,15 @@ public virtual async Task Create_index_tsvector_using_gin()
@"CREATE INDEX ""IX_Blogs_Title_Description"" ON ""Blogs"" USING GIN (to_tsvector('simple', ""Title"" || ' ' || coalesce(""Description"", '')));"
);
}
[
ConditionalFact
(
Skip
=
"https://github.com/npgsql/efcore.pg/issues/2267"
)]
public
override
Task
Alter_index_change_sort_order
()
=>
Task
.
CompletedTask
;
public
override
async
Task
Alter_index_change_sort_order
()
{
await
base
.
Alter_index_change_sort_order
();
AssertSql
(
@"DROP INDEX ""IX_People_X_Y_Z"";"
,
//
@"CREATE INDEX ""IX_People_X_Y_Z"" ON ""People"" (""X"", ""Y"" DESC, ""Z"");"
);
}
public
override
async
Task
Drop_index
()
{
...
...
test/EFCore.PG.FunctionalTests/Scaffolding/NpgsqlDatabaseModelFactoryTest.cs
浏览文件 @
08d8cc55
...
...
@@ -1665,12 +1665,12 @@ public void Index_collation()
@"DROP TABLE ""IndexCollation"""
);
[
Theory
]
[
InlineData
(
"gin"
,
n
ull
)]
[
InlineData
(
"gist"
,
n
ull
)]
[
InlineData
(
"hash"
,
n
ull
)]
[
InlineData
(
"brin"
,
n
ull
)]
[
InlineData
(
"btree"
,
new
[]
{
SortOrder
.
Ascending
,
SortOrder
.
Descending
})]
public
void
Index_
sort_order
(
string
method
,
SortOrder
[]
expected
)
[
InlineData
(
"gin"
,
n
ew
bool
[
0
]
)]
[
InlineData
(
"gist"
,
n
ew
bool
[
0
]
)]
[
InlineData
(
"hash"
,
n
ew
bool
[
0
]
)]
[
InlineData
(
"brin"
,
n
ew
bool
[
0
]
)]
[
InlineData
(
"btree"
,
new
[]
{
false
,
true
})]
public
void
Index_
IsDescending
(
string
method
,
bool
[]
expected
)
=>
Test
(
@"
CREATE TABLE ""IndexSortOrder"" (a text, b text, c tsvector);
CREATE INDEX ix_gin ON ""IndexSortOrder"" USING gin (c);
...
...
@@ -1686,10 +1686,11 @@ public void Index_sort_order(string method, SortOrder[] expected)
var
table
=
dbModel
.
Tables
.
Single
();
var
indexWith
=
table
.
Indexes
.
Single
(
i
=>
i
.
Name
==
$"ix_
{
method
}
"
);
Assert
.
Equal
(
expected
,
indexWith
.
FindAnnotation
(
NpgsqlAnnotationNames
.
IndexSortOrder
)?.
Value
);
// Assert.True(indexWith.IsDescending.SequenceEqual(expected));
Assert
.
Equal
(
expected
,
indexWith
.
IsDescending
);
var
indexWithout
=
table
.
Indexes
.
Single
(
i
=>
i
.
Name
==
"ix_without"
);
Assert
.
Null
(
indexWithout
.
FindAnnotation
(
NpgsqlAnnotationNames
.
IndexSortOrder
)
);
Assert
.
Equal
(
new
[]
{
false
,
false
},
indexWithout
.
IsDescending
);
},
@"DROP TABLE ""IndexSortOrder"""
);
...
...
@@ -1985,4 +1986,4 @@ public override async Task InitializeAsync()
protected
override
bool
ShouldLogCategory
(
string
logCategory
)
=>
logCategory
==
DbLoggerCategory
.
Scaffolding
.
Name
;
}
}
\ No newline at end of file
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录