Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
jobily
Efcore.Pg
提交
0f72c543
E
Efcore.Pg
项目概览
jobily
/
Efcore.Pg
9 个月 前同步成功
通知
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,体验更适合开发者的 AI 搜索 >>
未验证
提交
0f72c543
编写于
6月 28, 2023
作者:
S
Shay Rojansky
提交者:
GitHub
6月 28, 2023
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Translate DateTime.TimeOfDay and NodaTime LocalDateTime.Time (#2802)
Closes #2801
上级
555f972d
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
69 addition
and
72 deletion
+69
-72
src/EFCore.PG.NodaTime/Query/Internal/NpgsqlNodaTimeMemberTranslatorPlugin.cs
...me/Query/Internal/NpgsqlNodaTimeMemberTranslatorPlugin.cs
+31
-63
src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlDateTimeMemberTranslator.cs
...ionTranslators/Internal/NpgsqlDateTimeMemberTranslator.cs
+6
-5
test/EFCore.PG.FunctionalTests/Query/NorthwindWhereQueryNpgsqlTest.cs
...PG.FunctionalTests/Query/NorthwindWhereQueryNpgsqlTest.cs
+11
-0
test/EFCore.PG.NodaTime.FunctionalTests/NodaTimeQueryNpgsqlTest.cs
...re.PG.NodaTime.FunctionalTests/NodaTimeQueryNpgsqlTest.cs
+21
-4
未找到文件。
src/EFCore.PG.NodaTime/Query/Internal/NpgsqlNodaTimeMemberTranslatorPlugin.cs
浏览文件 @
0f72c543
...
...
@@ -282,74 +282,42 @@ SqlExpression Upper()
}
private
SqlExpression
?
TranslateDateTime
(
SqlExpression
instance
,
MemberInfo
member
,
Type
returnType
)
{
switch
(
member
.
Name
)
=>
member
.
Name
switch
{
case
"Year"
:
case
"Years"
:
return
GetDatePartExpression
(
instance
,
"year"
);
case
"Month"
:
case
"Months"
:
return
GetDatePartExpression
(
instance
,
"month"
);
case
"DayOfYear"
:
return
GetDatePartExpression
(
instance
,
"doy"
);
case
"Day"
:
case
"Days"
:
return
GetDatePartExpression
(
instance
,
"day"
);
case
"Hour"
:
case
"Hours"
:
return
GetDatePartExpression
(
instance
,
"hour"
);
case
"Minute"
:
case
"Minutes"
:
return
GetDatePartExpression
(
instance
,
"minute"
);
case
"Second"
:
case
"Seconds"
:
return
GetDatePartExpression
(
instance
,
"second"
,
true
);
case
"Millisecond"
:
case
"Milliseconds"
:
return
null
;
// Too annoying
case
"DayOfWeek"
:
// Unlike DateTime.DayOfWeek, NodaTime's IsoDayOfWeek enum doesn't exactly correspond to PostgreSQL's
// values returned by date_part('dow', ...): in NodaTime Sunday is 7 and not 0, which is None.
// So we generate a CASE WHEN expression to translate PostgreSQL's 0 to 7.
var
getValueExpression
=
GetDatePartExpression
(
instance
,
"dow"
,
true
);
// TODO: Can be simplified once https://github.com/aspnet/EntityFrameworkCore/pull/16726 is in
return
_sqlExpressionFactory
.
Case
(
new
[]
{
new
CaseWhenClause
(
_sqlExpressionFactory
.
Equal
(
getValueExpression
,
_sqlExpressionFactory
.
Constant
(
0
)),
_sqlExpressionFactory
.
Constant
(
7
))
},
getValueExpression
);
"Year"
or
"Years"
=>
GetDatePartExpression
(
instance
,
"year"
),
"Month"
or
"Months"
=>
GetDatePartExpression
(
instance
,
"month"
),
"DayOfYear"
=>
GetDatePartExpression
(
instance
,
"doy"
),
"Day"
or
"Days"
=>
GetDatePartExpression
(
instance
,
"day"
),
"Hour"
or
"Hours"
=>
GetDatePartExpression
(
instance
,
"hour"
),
"Minute"
or
"Minutes"
=>
GetDatePartExpression
(
instance
,
"minute"
),
"Second"
or
"Seconds"
=>
GetDatePartExpression
(
instance
,
"second"
,
true
),
"Millisecond"
or
"Milliseconds"
=>
null
,
// Too annoying
// Unlike DateTime.DayOfWeek, NodaTime's IsoDayOfWeek enum doesn't exactly correspond to PostgreSQL's
// values returned by date_part('dow', ...): in NodaTime Sunday is 7 and not 0, which is None.
// So we generate a CASE WHEN expression to translate PostgreSQL's 0 to 7.
"DayOfWeek"
when
GetDatePartExpression
(
instance
,
"dow"
,
true
)
is
var
getValueExpression
=>
_sqlExpressionFactory
.
Case
(
getValueExpression
,
new
[]
{
new
CaseWhenClause
(
_sqlExpressionFactory
.
Constant
(
0
),
_sqlExpressionFactory
.
Constant
(
7
))
},
getValueExpression
),
// PG allows converting a timestamp directly to date, truncating the time; but given a timestamptz, it performs a time zone
// conversion (based on TimeZone), which we don't want (so avoid translating except on timestamp).
// The translation for ZonedDateTime.Date converts to timestamp before ending up here.
case
"Date"
when
instance
.
TypeMapping
is
TimestampLocalDateTimeMapping
or
LegacyTimestampInstantMapping
:
return
_sqlExpressionFactory
.
Convert
(
instance
,
typeof
(
LocalDate
),
_typeMappingSource
.
FindMapping
(
typeof
(
LocalDate
))!);
case
"TimeOfDay"
:
// TODO: Technically possible simply via casting to PG time,
// but ExplicitCastExpression only allows casting to PG types that
// are default-mapped from CLR types (timespan maps to interval,
// which timestamp cannot be cast into)
return
null
;
default
:
return
null
;
}
}
"Date"
when
instance
.
TypeMapping
is
TimestampLocalDateTimeMapping
or
LegacyTimestampInstantMapping
=>
_sqlExpressionFactory
.
Convert
(
instance
,
typeof
(
LocalDate
),
_typeMappingSource
.
FindMapping
(
typeof
(
LocalDate
))!),
"TimeOfDay"
=>
_sqlExpressionFactory
.
Convert
(
instance
,
typeof
(
LocalTime
),
_typeMappingSource
.
FindMapping
(
typeof
(
LocalTime
),
storeTypeName
:
"time"
)),
_
=>
null
};
/// <summary>
/// Constructs the date_part expression.
...
...
src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlDateTimeMemberTranslator.cs
浏览文件 @
0f72c543
...
...
@@ -12,6 +12,7 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query.ExpressionTranslators.Inte
/// </remarks>
public
class
NpgsqlDateTimeMemberTranslator
:
IMemberTranslator
{
private
readonly
IRelationalTypeMappingSource
_typeMappingSource
;
private
readonly
NpgsqlSqlExpressionFactory
_sqlExpressionFactory
;
private
readonly
RelationalTypeMapping
_timestampMapping
;
private
readonly
RelationalTypeMapping
_timestampTzMapping
;
...
...
@@ -26,6 +27,7 @@ public class NpgsqlDateTimeMemberTranslator : IMemberTranslator
IRelationalTypeMappingSource
typeMappingSource
,
NpgsqlSqlExpressionFactory
sqlExpressionFactory
)
{
_typeMappingSource
=
typeMappingSource
;
_timestampMapping
=
typeMappingSource
.
FindMapping
(
"timestamp without time zone"
)!;
_timestampTzMapping
=
typeMappingSource
.
FindMapping
(
"timestamp with time zone"
)!;
_sqlExpressionFactory
=
sqlExpressionFactory
;
...
...
@@ -128,11 +130,10 @@ public class NpgsqlDateTimeMemberTranslator : IMemberTranslator
// .NET's DayOfWeek is an enum, but its int values happen to correspond to PostgreSQL
nameof
(
DateTime
.
DayOfWeek
)
=>
GetDatePartExpression
(
instance
!,
"dow"
,
floor
:
true
),
// TODO: Technically possible simply via casting to PG time, should be better in EF Core 3.0
// but ExplicitCastExpression only allows casting to PG types that
// are default-mapped from CLR types (timespan maps to interval,
// which timestamp cannot be cast into)
nameof
(
DateTime
.
TimeOfDay
)
=>
null
,
nameof
(
DateTime
.
TimeOfDay
)
=>
_sqlExpressionFactory
.
Convert
(
instance
!,
typeof
(
TimeSpan
),
_typeMappingSource
.
FindMapping
(
typeof
(
TimeSpan
),
storeTypeName
:
"time"
)),
// TODO: Should be possible
nameof
(
DateTime
.
Ticks
)
=>
null
,
...
...
test/EFCore.PG.FunctionalTests/Query/NorthwindWhereQueryNpgsqlTest.cs
浏览文件 @
0f72c543
...
...
@@ -33,6 +33,17 @@ WHERE date_trunc('day', now()::timestamp) = date_trunc('day', now()::timestamp)
""");
}
public
override
async
Task
Time_of_day_datetime
(
bool
async
)
{
await
base
.
Time_of_day_datetime
(
async
);
AssertSql
(
"""
SELECT
o
.
"OrderDate"
::
time
FROM
"Orders"
AS
o
""");
}
public
override
async
Task
Where_datetime_date_component
(
bool
async
)
{
await
base
.
Where_datetime_date_component
(
async
);
...
...
test/EFCore.PG.NodaTime.FunctionalTests/NodaTimeQueryNpgsqlTest.cs
浏览文件 @
0f72c543
...
...
@@ -311,6 +311,23 @@ public async Task LocalDateTime_Date(bool async)
""");
}
[
ConditionalTheory
]
[
MemberData
(
nameof
(
IsAsyncData
))]
public
async
Task
LocalDateTime_Time
(
bool
async
)
{
await
AssertQuery
(
async
,
ss
=>
ss
.
Set
<
NodaTimeTypes
>().
Where
(
t
=>
t
.
LocalDateTime
.
TimeOfDay
==
new
LocalTime
(
10
,
31
,
33
,
666
)),
entryCount
:
1
);
AssertSql
(
"""
SELECT
n
.
"Id"
,
n
.
"DateInterval"
,
n
.
"Duration"
,
n
.
"Instant"
,
n
.
"InstantRange"
,
n
.
"Interval"
,
n
.
"LocalDate"
,
n
.
"LocalDate2"
,
n
.
"LocalDateRange"
,
n
.
"LocalDateTime"
,
n
.
"LocalTime"
,
n
.
"Long"
,
n
.
"OffsetTime"
,
n
.
"Period"
,
n
.
"TimeZoneId"
,
n
.
"ZonedDateTime"
FROM
"NodaTimeTypes"
AS
n
WHERE
n
.
"LocalDateTime"
::
time
=
TIME
'
10
:
31
:
33.666
'
""");
}
[
ConditionalTheory
]
[
MemberData
(
nameof
(
IsAsyncData
))]
public
async
Task
LocalDateTime_DayOfWeek
(
bool
async
)
...
...
@@ -324,8 +341,8 @@ public async Task LocalDateTime_DayOfWeek(bool async)
"""
SELECT
n
.
"Id"
,
n
.
"DateInterval"
,
n
.
"Duration"
,
n
.
"Instant"
,
n
.
"InstantRange"
,
n
.
"Interval"
,
n
.
"LocalDate"
,
n
.
"LocalDate2"
,
n
.
"LocalDateRange"
,
n
.
"LocalDateTime"
,
n
.
"LocalTime"
,
n
.
"Long"
,
n
.
"OffsetTime"
,
n
.
"Period"
,
n
.
"TimeZoneId"
,
n
.
"ZonedDateTime"
FROM
"NodaTimeTypes"
AS
n
WHERE
CASE
WHEN
floor
(
date_part
(
'
dow
'
,
n
.
"LocalDateTime"
))::
int
=
0
THEN
7
WHERE
CASE
floor
(
date_part
(
'
dow
'
,
n
.
"LocalDateTime"
))::
int
WHEN
0
THEN
7
ELSE
floor
(
date_part
(
'
dow
'
,
n
.
"LocalDateTime"
))::
int
END
=
5
""");
...
...
@@ -1812,8 +1829,8 @@ public async Task ZonedDateTime_DayOfWeek(bool async)
"""
SELECT
n
.
"Id"
,
n
.
"DateInterval"
,
n
.
"Duration"
,
n
.
"Instant"
,
n
.
"InstantRange"
,
n
.
"Interval"
,
n
.
"LocalDate"
,
n
.
"LocalDate2"
,
n
.
"LocalDateRange"
,
n
.
"LocalDateTime"
,
n
.
"LocalTime"
,
n
.
"Long"
,
n
.
"OffsetTime"
,
n
.
"Period"
,
n
.
"TimeZoneId"
,
n
.
"ZonedDateTime"
FROM
"NodaTimeTypes"
AS
n
WHERE
CASE
WHEN
floor
(
date_part
(
'
dow
'
,
n
.
"ZonedDateTime"
AT
TIME
ZONE
'
UTC
'
))::
int
=
0
THEN
7
WHERE
CASE
floor
(
date_part
(
'
dow
'
,
n
.
"ZonedDateTime"
AT
TIME
ZONE
'
UTC
'
))::
int
WHEN
0
THEN
7
ELSE
floor
(
date_part
(
'
dow
'
,
n
.
"ZonedDateTime"
AT
TIME
ZONE
'
UTC
'
))::
int
END
=
5
""");
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录