Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
jobily
Efcore.Pg
提交
ddc63fc2
E
Efcore.Pg
项目概览
jobily
/
Efcore.Pg
10 个月 前同步成功
通知
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,发现更多精彩内容 >>
提交
ddc63fc2
编写于
8月 31, 2022
作者:
S
Shay Rojansky
1
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Correct LTree type mapping logic
Fixes #2487
上级
07400f75
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
70 addition
and
21 deletion
+70
-21
src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlLTreeTranslator.cs
...y/ExpressionTranslators/Internal/NpgsqlLTreeTranslator.cs
+31
-17
test/EFCore.PG.FunctionalTests/Query/LTreeQueryTest.cs
test/EFCore.PG.FunctionalTests/Query/LTreeQueryTest.cs
+39
-4
未找到文件。
src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlLTreeTranslator.cs
浏览文件 @
ddc63fc2
...
...
@@ -57,32 +57,32 @@ public class NpgsqlLTreeTranslator : IMethodCallTranslator, IMemberTranslator
nameof
(
LTree
.
IsAncestorOf
)
=>
new
PostgresBinaryExpression
(
PostgresExpressionType
.
Contains
,
_sqlExpressionFactory
.
ApplyTypeMapping
(
instance
!,
_ltreeTypeMapping
),
_sqlExpressionFactory
.
ApplyTypeMapping
(
arguments
[
0
],
_ltreeTypeMapping
),
ApplyTypeMappingOrConvert
(
instance
!,
_ltreeTypeMapping
),
ApplyTypeMappingOrConvert
(
arguments
[
0
],
_ltreeTypeMapping
),
typeof
(
bool
),
_boolTypeMapping
),
nameof
(
LTree
.
IsDescendantOf
)
=>
new
PostgresBinaryExpression
(
PostgresExpressionType
.
ContainedBy
,
_sqlExpressionFactory
.
ApplyTypeMapping
(
instance
!,
_ltreeTypeMapping
),
_sqlExpressionFactory
.
ApplyTypeMapping
(
arguments
[
0
],
_ltreeTypeMapping
),
ApplyTypeMappingOrConvert
(
instance
!,
_ltreeTypeMapping
),
ApplyTypeMappingOrConvert
(
arguments
[
0
],
_ltreeTypeMapping
),
typeof
(
bool
),
_boolTypeMapping
),
nameof
(
LTree
.
MatchesLQuery
)
=>
new
PostgresBinaryExpression
(
PostgresExpressionType
.
LTreeMatches
,
_sqlExpressionFactory
.
ApplyTypeMapping
(
instance
!,
_ltreeTypeMapping
),
_sqlExpressionFactory
.
ApplyTypeMapping
(
arguments
[
0
],
_lqueryTypeMapping
),
ApplyTypeMappingOrConvert
(
instance
!,
_ltreeTypeMapping
),
ApplyTypeMappingOrConvert
(
arguments
[
0
],
_lqueryTypeMapping
),
typeof
(
bool
),
_boolTypeMapping
),
nameof
(
LTree
.
MatchesLTxtQuery
)
=>
new
PostgresBinaryExpression
(
PostgresExpressionType
.
LTreeMatches
,
_sqlExpressionFactory
.
ApplyTypeMapping
(
instance
!,
_ltreeTypeMapping
),
_sqlExpressionFactory
.
ApplyTypeMapping
(
arguments
[
0
],
_ltxtqueryTypeMapping
),
ApplyTypeMappingOrConvert
(
instance
!,
_ltreeTypeMapping
),
ApplyTypeMappingOrConvert
(
arguments
[
0
],
_ltxtqueryTypeMapping
),
typeof
(
bool
),
_boolTypeMapping
),
...
...
@@ -171,7 +171,7 @@ public class NpgsqlLTreeTranslator : IMethodCallTranslator, IMemberTranslator
{
return
new
PostgresBinaryExpression
(
PostgresExpressionType
.
LTreeMatchesAny
,
_sqlExpressionFactory
.
ApplyTypeMapping
(
Visit
(
predicateInstance
),
_ltreeTypeMapping
),
ApplyTypeMappingOrConvert
(
Visit
(
predicateInstance
),
_ltreeTypeMapping
),
_sqlExpressionFactory
.
ApplyTypeMapping
(
Visit
(
array
),
_lqueryArrayTypeMapping
),
typeof
(
bool
),
_boolTypeMapping
);
...
...
@@ -184,7 +184,7 @@ public class NpgsqlLTreeTranslator : IMethodCallTranslator, IMemberTranslator
return
new
PostgresBinaryExpression
(
PostgresExpressionType
.
Contains
,
_sqlExpressionFactory
.
ApplyTypeMapping
(
Visit
(
array
),
_ltreeArrayTypeMapping
),
_sqlExpressionFactory
.
ApplyTypeMapping
(
Visit
(
predicateArguments
[
0
]),
_ltreeTypeMapping
),
ApplyTypeMappingOrConvert
(
Visit
(
predicateArguments
[
0
]),
_ltreeTypeMapping
),
typeof
(
bool
),
_boolTypeMapping
);
}
...
...
@@ -196,7 +196,7 @@ public class NpgsqlLTreeTranslator : IMethodCallTranslator, IMemberTranslator
return
new
PostgresBinaryExpression
(
PostgresExpressionType
.
ContainedBy
,
_sqlExpressionFactory
.
ApplyTypeMapping
(
Visit
(
array
),
_ltreeArrayTypeMapping
),
_sqlExpressionFactory
.
ApplyTypeMapping
(
Visit
(
predicateArguments
[
0
]),
_ltreeTypeMapping
),
ApplyTypeMappingOrConvert
(
Visit
(
predicateArguments
[
0
]),
_ltreeTypeMapping
),
typeof
(
bool
),
_boolTypeMapping
);
}
...
...
@@ -208,7 +208,7 @@ public class NpgsqlLTreeTranslator : IMethodCallTranslator, IMemberTranslator
return
new
PostgresBinaryExpression
(
PostgresExpressionType
.
LTreeMatches
,
_sqlExpressionFactory
.
ApplyTypeMapping
(
Visit
(
array
),
_ltreeArrayTypeMapping
),
_sqlExpressionFactory
.
ApplyTypeMapping
(
Visit
(
predicateArguments
[
0
]),
_lqueryTypeMapping
),
ApplyTypeMappingOrConvert
(
Visit
(
predicateArguments
[
0
]),
_lqueryTypeMapping
),
typeof
(
bool
),
_boolTypeMapping
);
}
...
...
@@ -220,7 +220,7 @@ public class NpgsqlLTreeTranslator : IMethodCallTranslator, IMemberTranslator
return
new
PostgresBinaryExpression
(
PostgresExpressionType
.
LTreeMatches
,
_sqlExpressionFactory
.
ApplyTypeMapping
(
Visit
(
array
),
_ltreeArrayTypeMapping
),
_sqlExpressionFactory
.
ApplyTypeMapping
(
Visit
(
predicateArguments
[
0
]),
_ltxtqueryTypeMapping
),
ApplyTypeMappingOrConvert
(
Visit
(
predicateArguments
[
0
]),
_ltxtqueryTypeMapping
),
typeof
(
bool
),
_boolTypeMapping
);
}
...
...
@@ -267,7 +267,7 @@ public class NpgsqlLTreeTranslator : IMethodCallTranslator, IMemberTranslator
return
new
PostgresBinaryExpression
(
PostgresExpressionType
.
LTreeFirstAncestor
,
_sqlExpressionFactory
.
ApplyTypeMapping
(
Visit
(
array
),
_ltreeArrayTypeMapping
),
_sqlExpressionFactory
.
ApplyTypeMapping
(
Visit
(
predicateArguments
[
0
]),
_ltreeTypeMapping
),
ApplyTypeMappingOrConvert
(
Visit
(
predicateArguments
[
0
]),
_ltreeTypeMapping
),
typeof
(
LTree
),
_ltreeTypeMapping
);
}
...
...
@@ -279,7 +279,7 @@ public class NpgsqlLTreeTranslator : IMethodCallTranslator, IMemberTranslator
return
new
PostgresBinaryExpression
(
PostgresExpressionType
.
LTreeFirstDescendent
,
_sqlExpressionFactory
.
ApplyTypeMapping
(
Visit
(
array
),
_ltreeArrayTypeMapping
),
_sqlExpressionFactory
.
ApplyTypeMapping
(
Visit
(
predicateArguments
[
0
]),
_ltreeTypeMapping
),
ApplyTypeMappingOrConvert
(
Visit
(
predicateArguments
[
0
]),
_ltreeTypeMapping
),
typeof
(
LTree
),
_ltreeTypeMapping
);
}
...
...
@@ -291,7 +291,7 @@ public class NpgsqlLTreeTranslator : IMethodCallTranslator, IMemberTranslator
return
new
PostgresBinaryExpression
(
PostgresExpressionType
.
LTreeFirstMatches
,
_sqlExpressionFactory
.
ApplyTypeMapping
(
Visit
(
array
),
_ltreeArrayTypeMapping
),
_sqlExpressionFactory
.
ApplyTypeMapping
(
Visit
(
predicateArguments
[
0
]),
_lqueryTypeMapping
),
ApplyTypeMappingOrConvert
(
Visit
(
predicateArguments
[
0
]),
_lqueryTypeMapping
),
typeof
(
LTree
),
_ltreeTypeMapping
);
}
...
...
@@ -303,7 +303,7 @@ public class NpgsqlLTreeTranslator : IMethodCallTranslator, IMemberTranslator
return
new
PostgresBinaryExpression
(
PostgresExpressionType
.
LTreeFirstMatches
,
_sqlExpressionFactory
.
ApplyTypeMapping
(
Visit
(
array
),
_ltreeArrayTypeMapping
),
_sqlExpressionFactory
.
ApplyTypeMapping
(
Visit
(
predicateArguments
[
0
]),
_ltxtqueryTypeMapping
),
ApplyTypeMappingOrConvert
(
Visit
(
predicateArguments
[
0
]),
_ltxtqueryTypeMapping
),
typeof
(
string
),
_ltreeTypeMapping
);
}
...
...
@@ -315,4 +315,18 @@ public class NpgsqlLTreeTranslator : IMethodCallTranslator, IMemberTranslator
SqlExpression
Visit
(
Expression
expression
)
=>
(
SqlExpression
)
sqlTranslatingExpressionVisitor
.
Visit
(
expression
);
}
// Applying e.g. the LQuery type mapping on a function operator is a bit tricky.
// If it's a constant, we can just apply the mapping: the constant will get rendered as an untyped string literal, and PG will
// coerce it as the function parameter.
// If it's a parameter, we can also just apply the mapping (which causes NpgsqlDbType to be set to LQuery).
// For anything else, we may need an explicit cast to LQuery, e.g. a plain text column or a concatenation between strings;
// apply the default type mapping and then apply an additional Convert node if the resulting mapping isn't what we need.
private
SqlExpression
ApplyTypeMappingOrConvert
(
SqlExpression
sqlExpression
,
RelationalTypeMapping
typeMapping
)
=>
sqlExpression
is
SqlConstantExpression
or
SqlParameterExpression
?
_sqlExpressionFactory
.
ApplyTypeMapping
(
sqlExpression
,
typeMapping
)
:
_sqlExpressionFactory
.
ApplyDefaultTypeMapping
(
sqlExpression
)
is
var
expressionWithDefaultTypeMapping
&&
expressionWithDefaultTypeMapping
.
TypeMapping
!.
StoreType
==
typeMapping
.
StoreType
?
expressionWithDefaultTypeMapping
:
_sqlExpressionFactory
.
Convert
(
expressionWithDefaultTypeMapping
,
typeMapping
.
ClrType
,
typeMapping
);
}
\ No newline at end of file
test/EFCore.PG.FunctionalTests/Query/LTreeQueryTest.cs
浏览文件 @
ddc63fc2
...
...
@@ -128,13 +128,44 @@ public void LTree_matches_LQuery()
Assert
.
Equal
(
4
,
entity
.
Id
);
AssertSql
(
"""
SELECT
l
.
"Id"
,
l
.
"Path"
,
l
.
"PathAsString"
SELECT
l
.
"Id"
,
l
.
"Path"
,
l
.
"PathAsString"
,
l
.
"SomeString"
FROM
"LTreeEntities"
AS
l
WHERE
l
.
"Path"
~
'
*.
Astrophysics
'
LIMIT
2
""");
}
[
ConditionalFact
]
// #2487
public
void
LTree_matches_LQuery_with_string_column
()
{
using
var
ctx
=
CreateContext
();
var
entity
=
ctx
.
LTreeEntities
.
Single
(
l
=>
l
.
Path
.
MatchesLQuery
(
l
.
SomeString
));
Assert
.
Equal
(
4
,
entity
.
Id
);
AssertSql
(
"""
SELECT
l
.
"Id"
,
l
.
"Path"
,
l
.
"PathAsString"
,
l
.
"SomeString"
FROM
"LTreeEntities"
AS
l
WHERE
l
.
"Path"
~
l
.
"SomeString"
::
lquery
LIMIT
2
""");
}
[
ConditionalFact
]
// #2487
public
void
LTree_matches_LQuery_with_concat
()
{
using
var
ctx
=
CreateContext
();
var
count
=
ctx
.
LTreeEntities
.
Count
(
l
=>
l
.
Path
.
MatchesLQuery
(
"*.Astrophysics."
+
l
.
Id
));
Assert
.
Equal
(
0
,
count
);
AssertSql
(
"""
SELECT
count
(*)::
int
FROM
"LTreeEntities"
AS
l
WHERE
l
.
"Path"
~
CAST
((
'
*.
Astrophysics
.
'
||
l
.
"Id"
::
text
)
AS
lquery
)
""");
}
[
ConditionalFact
]
public
void
LTree_matches_any_LQuery
()
{
...
...
@@ -147,7 +178,7 @@ public void LTree_matches_any_LQuery()
"""
@__lqueries_0
={
'
*.
Astrophysics
'
,
'
*.
Geology
'
}
(
DbType
=
Object
)
SELECT
l
.
"Id"
,
l
.
"Path"
,
l
.
"PathAsString"
SELECT
l
.
"Id"
,
l
.
"Path"
,
l
.
"PathAsString"
,
l
.
"SomeString"
FROM
"LTreeEntities"
AS
l
WHERE
l
.
"Path"
?
@__lqueries_0
LIMIT
2
...
...
@@ -178,7 +209,7 @@ public void LTree_concat()
Assert
.
Equal
(
2
,
entity
.
Id
);
AssertSql
(
"""
SELECT
l
.
"Id"
,
l
.
"Path"
,
l
.
"PathAsString"
SELECT
l
.
"Id"
,
l
.
"Path"
,
l
.
"PathAsString"
,
l
.
"SomeString"
FROM
"LTreeEntities"
AS
l
WHERE
(
l
.
"Path"
::
text
||
'
.
Astronomy
'
)
=
'
Top
.
Science
.
Astronomy
'
LIMIT
2
...
...
@@ -395,7 +426,7 @@ public void Subpath2()
Assert
.
Equal
(
4
,
result
.
Id
);
AssertSql
(
"""
SELECT
l
.
"Id"
,
l
.
"Path"
,
l
.
"PathAsString"
SELECT
l
.
"Id"
,
l
.
"Path"
,
l
.
"PathAsString"
,
l
.
"SomeString"
FROM
"LTreeEntities"
AS
l
WHERE
nlevel
(
l
.
"Path"
)
>
2
AND
subpath
(
l
.
"Path"
,
2
)
=
'
Astronomy
.
Astrophysics
'
LIMIT
2
...
...
@@ -495,6 +526,7 @@ public static void Seed(LTreeQueryContext context)
foreach
(
var
ltreeEntity
in
ltreeEntities
)
{
ltreeEntity
.
PathAsString
=
ltreeEntity
.
Path
;
ltreeEntity
.
SomeString
=
"*.Astrophysics"
;
}
context
.
LTreeEntities
.
AddRange
(
ltreeEntities
);
...
...
@@ -512,6 +544,9 @@ public class LTreeEntity
[
Required
]
[
Column
(
TypeName
=
"ltree"
)]
public
string
PathAsString
{
get
;
set
;
}
[
Required
]
public
string
SomeString
{
get
;
set
;
}
}
public
class
LTreeQueryFixture
:
SharedStoreFixtureBase
<
LTreeQueryContext
>
...
...
jobily
@jobily
mentioned in commit
9b2a90cc
·
9月 18, 2023
mentioned in commit
9b2a90cc
mentioned in commit 9b2a90ccbbbff04e025c63a2d4b17278db17b829
开关提交列表
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录