Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Dapper
提交
49adbe1e
D
Dapper
项目概览
int
/
Dapper
11 个月 前同步成功
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
Dapper
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
49adbe1e
编写于
6月 14, 2011
作者:
S
Sam Saffron
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Added support for a multi mapping grid reader
上级
d8b19a45
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
227 addition
and
94 deletion
+227
-94
Dapper/SqlMapper.cs
Dapper/SqlMapper.cs
+181
-94
Tests/Tests.cs
Tests/Tests.cs
+46
-0
未找到文件。
Dapper/SqlMapper.cs
浏览文件 @
49adbe1e
...
...
@@ -214,6 +214,12 @@ internal Identity ForGrid(Type primaryType, int gridIndex)
{
return
new
Identity
(
sql
,
connectionString
,
primaryType
,
parametersType
,
null
,
gridIndex
);
}
internal
Identity
ForGrid
(
Type
primaryType
,
Type
[]
otherTypes
,
int
gridIndex
)
{
return
new
Identity
(
sql
,
connectionString
,
primaryType
,
parametersType
,
otherTypes
,
gridIndex
);
}
internal
Identity
(
string
sql
,
IDbConnection
connection
,
Type
type
,
Type
parametersType
,
Type
[]
otherTypes
)
:
this
(
sql
,
connection
.
ConnectionString
,
type
,
parametersType
,
otherTypes
,
0
)
{
}
...
...
@@ -473,137 +479,161 @@ class DontMap { }
static
IEnumerable
<
TReturn
>
MultiMap
<
TFirst
,
TSecond
,
TThird
,
TFourth
,
TFifth
,
TReturn
>(
this
IDbConnection
cnn
,
string
sql
,
object
map
,
object
param
,
IDbTransaction
transaction
,
bool
buffered
,
string
splitOn
,
int
?
commandTimeout
,
CommandType
?
commandType
)
{
var
results
=
MultiMapImpl
<
TFirst
,
TSecond
,
TThird
,
TFourth
,
TFifth
,
TReturn
>(
cnn
,
sql
,
map
,
param
,
transaction
,
splitOn
,
commandTimeout
,
commandType
);
var
results
=
MultiMapImpl
<
TFirst
,
TSecond
,
TThird
,
TFourth
,
TFifth
,
TReturn
>(
cnn
,
sql
,
map
,
param
,
transaction
,
splitOn
,
commandTimeout
,
commandType
,
null
,
null
);
return
buffered
?
results
.
ToList
()
:
results
;
}
static
IEnumerable
<
TReturn
>
MultiMapImpl
<
TFirst
,
TSecond
,
TThird
,
TFourth
,
TFifth
,
TReturn
>(
this
IDbConnection
cnn
,
string
sql
,
object
map
,
object
param
,
IDbTransaction
transaction
,
string
splitOn
,
int
?
commandTimeout
,
CommandType
?
commandType
)
static
IEnumerable
<
TReturn
>
MultiMapImpl
<
TFirst
,
TSecond
,
TThird
,
TFourth
,
TFifth
,
TReturn
>(
this
IDbConnection
cnn
,
string
sql
,
object
map
,
object
param
,
IDbTransaction
transaction
,
string
splitOn
,
int
?
commandTimeout
,
CommandType
?
commandType
,
IDataReader
reader
,
Identity
identity
)
{
Identity
identity
=
new
Identity
(
sql
,
cnn
,
typeof
(
TFirst
),
(
object
)
param
==
null
?
null
:
((
object
)
param
).
GetType
(),
new
[]
{
typeof
(
TFirst
),
typeof
(
TSecond
),
typeof
(
TThird
),
typeof
(
TFourth
),
typeof
(
TFifth
)
});
identity
=
identity
??
new
Identity
(
sql
,
cnn
,
typeof
(
TFirst
),
(
object
)
param
==
null
?
null
:
((
object
)
param
).
GetType
(),
new
[]
{
typeof
(
TFirst
),
typeof
(
TSecond
),
typeof
(
TThird
),
typeof
(
TFourth
),
typeof
(
TFifth
)
});
CacheInfo
info
=
GetCacheInfo
(
identity
);
using
(
var
cmd
=
SetupCommand
(
cnn
,
transaction
,
sql
,
info
.
ParamReader
,
(
object
)
param
,
commandTimeout
,
commandType
))
IDbCommand
ownedCommand
=
null
;
IDataReader
ownedReader
=
null
;
try
{
using
(
var
reader
=
cmd
.
ExecuteReader
()
)
if
(
reader
==
null
)
{
if
(
info
.
Deserializer
==
null
)
{
int
current
=
0
;
var
splits
=
splitOn
.
Split
(
','
).
ToArray
();
var
splitIndex
=
0
;
Func
<
int
>
nextSplit
=
()
=>
{
var
currentSplit
=
splits
[
splitIndex
];
if
(
splits
.
Length
>
splitIndex
+
1
)
{
splitIndex
++;
}
int
pos
;
for
(
pos
=
current
+
1
;
pos
<
reader
.
FieldCount
;
pos
++)
{
// some people like ID some id ... assuming case insensitive splits for now
if
(
splitOn
==
"*"
||
string
.
Equals
(
reader
.
GetName
(
pos
),
currentSplit
,
StringComparison
.
InvariantCultureIgnoreCase
))
{
break
;
}
}
current
=
pos
;
return
pos
;
};
ownedCommand
=
SetupCommand
(
cnn
,
transaction
,
sql
,
info
.
ParamReader
,
(
object
)
param
,
commandTimeout
,
commandType
);
ownedReader
=
ownedCommand
.
ExecuteReader
();
reader
=
ownedReader
;
}
var
otherDeserializer
=
new
List
<
object
>();
if
(
info
.
Deserializer
==
null
)
{
int
current
=
0
;
int
split
=
nextSplit
();
info
.
Deserializer
=
GetDeserializer
<
TFirst
>(
reader
,
0
,
split
,
false
)
;
var
splits
=
splitOn
.
Split
(
','
).
ToArray
();
var
splitIndex
=
0
;
if
(
typeof
(
TSecond
)
!=
typeof
(
DontMap
))
{
var
next
=
nextSplit
();
otherDeserializer
.
Add
(
GetDeserializer
<
TSecond
>(
reader
,
split
,
next
-
split
,
true
));
split
=
next
;
}
if
(
typeof
(
TThird
)
!=
typeof
(
DontMap
))
{
var
next
=
nextSplit
();
otherDeserializer
.
Add
(
GetDeserializer
<
TThird
>(
reader
,
split
,
next
-
split
,
true
));
split
=
next
;
}
if
(
typeof
(
TFourth
)
!=
typeof
(
DontMap
))
Func
<
int
>
nextSplit
=
()
=>
{
var
currentSplit
=
splits
[
splitIndex
];
if
(
splits
.
Length
>
splitIndex
+
1
)
{
var
next
=
nextSplit
();
otherDeserializer
.
Add
(
GetDeserializer
<
TFourth
>(
reader
,
split
,
next
-
split
,
true
));
split
=
next
;
splitIndex
++;
}
if
(
typeof
(
TFifth
)
!=
typeof
(
DontMap
))
int
pos
;
for
(
pos
=
current
+
1
;
pos
<
reader
.
FieldCount
;
pos
++)
{
var
next
=
nextSplit
();
otherDeserializer
.
Add
(
GetDeserializer
<
TFifth
>(
reader
,
split
,
next
-
split
,
true
));
// some people like ID some id ... assuming case insensitive splits for now
if
(
splitOn
==
"*"
||
string
.
Equals
(
reader
.
GetName
(
pos
),
currentSplit
,
StringComparison
.
InvariantCultureIgnoreCase
))
{
break
;
}
}
current
=
pos
;
return
pos
;
};
var
otherDeserializer
=
new
List
<
object
>();
info
.
OtherDeserializers
=
otherDeserializer
.
ToArray
();
int
split
=
nextSplit
();
info
.
Deserializer
=
GetDeserializer
<
TFirst
>(
reader
,
0
,
split
,
false
);
SetQueryCache
(
identity
,
info
);
if
(
typeof
(
TSecond
)
!=
typeof
(
DontMap
))
{
var
next
=
nextSplit
();
otherDeserializer
.
Add
(
GetDeserializer
<
TSecond
>(
reader
,
split
,
next
-
split
,
true
));
split
=
next
;
}
if
(
typeof
(
TThird
)
!=
typeof
(
DontMap
))
{
var
next
=
nextSplit
();
otherDeserializer
.
Add
(
GetDeserializer
<
TThird
>(
reader
,
split
,
next
-
split
,
true
));
split
=
next
;
}
if
(
typeof
(
TFourth
)
!=
typeof
(
DontMap
))
{
var
next
=
nextSplit
();
otherDeserializer
.
Add
(
GetDeserializer
<
TFourth
>(
reader
,
split
,
next
-
split
,
true
));
split
=
next
;
}
if
(
typeof
(
TFifth
)
!=
typeof
(
DontMap
))
{
var
next
=
nextSplit
();
otherDeserializer
.
Add
(
GetDeserializer
<
TFifth
>(
reader
,
split
,
next
-
split
,
true
));
}
var
deserializer
=
(
Func
<
IDataReader
,
TFirst
>)
info
.
Deserializer
;
var
deserializer2
=
(
Func
<
IDataReader
,
TSecond
>)
info
.
OtherDeserializers
[
0
];
info
.
OtherDeserializers
=
otherDeserializer
.
ToArray
();
SetQueryCache
(
identity
,
info
);
}
var
deserializer
=
(
Func
<
IDataReader
,
TFirst
>)
info
.
Deserializer
;
var
deserializer2
=
(
Func
<
IDataReader
,
TSecond
>)
info
.
OtherDeserializers
[
0
];
Func
<
IDataReader
,
TReturn
>
mapIt
=
null
;
if
(
info
.
OtherDeserializers
.
Length
==
1
)
{
mapIt
=
r
=>
((
Func
<
TFirst
,
TSecond
,
TReturn
>)
map
)(
deserializer
(
r
),
deserializer2
(
r
));
}
Func
<
IDataReader
,
TReturn
>
mapIt
=
null
;
if
(
info
.
OtherDeserializers
.
Length
>
1
)
{
var
deserializer3
=
(
Func
<
IDataReader
,
TThird
>)
info
.
OtherDeserializers
[
1
];
if
(
info
.
OtherDeserializers
.
Length
==
1
)
if
(
info
.
OtherDeserializers
.
Length
==
2
)
{
mapIt
=
r
=>
((
Func
<
TFirst
,
TSecond
,
T
Return
>)
map
)(
deserializer
(
r
),
deserializer2
(
r
));
mapIt
=
r
=>
((
Func
<
TFirst
,
TSecond
,
T
Third
,
TReturn
>)
map
)(
deserializer
(
r
),
deserializer2
(
r
),
deserializer3
(
r
));
}
if
(
info
.
OtherDeserializers
.
Length
>
1
)
if
(
info
.
OtherDeserializers
.
Length
>
2
)
{
var
deserializer3
=
(
Func
<
IDataReader
,
TThird
>)
info
.
OtherDeserializers
[
1
];
if
(
info
.
OtherDeserializers
.
Length
==
2
)
var
deserializer4
=
(
Func
<
IDataReader
,
TFourth
>)
info
.
OtherDeserializers
[
2
];
if
(
info
.
OtherDeserializers
.
Length
==
3
)
{
mapIt
=
r
=>
((
Func
<
TFirst
,
TSecond
,
TThird
,
T
Return
>)
map
)(
deserializer
(
r
),
deserializer2
(
r
),
deserializer3
(
r
));
mapIt
=
r
=>
((
Func
<
TFirst
,
TSecond
,
TThird
,
T
Fourth
,
TReturn
>)
map
)(
deserializer
(
r
),
deserializer2
(
r
),
deserializer3
(
r
),
deserializer4
(
r
));
}
if
(
info
.
OtherDeserializers
.
Length
>
2
)
{
var
deserializer4
=
(
Func
<
IDataReader
,
TFourth
>)
info
.
OtherDeserializers
[
2
];
if
(
info
.
OtherDeserializers
.
Length
==
3
)
{
mapIt
=
r
=>
((
Func
<
TFirst
,
TSecond
,
TThird
,
TFourth
,
TReturn
>)
map
)(
deserializer
(
r
),
deserializer2
(
r
),
deserializer3
(
r
),
deserializer4
(
r
));
}
if
(
info
.
OtherDeserializers
.
Length
>
3
)
{
if
(
info
.
OtherDeserializers
.
Length
>
3
)
{
#if CSHARP30
throw
new
NotSupportedException
();
throw
new
NotSupportedException
();
#else
var
deserializer5
=
(
Func
<
IDataReader
,
TFifth
>)
info
.
OtherDeserializers
[
3
];
mapIt
=
r
=>
((
Func
<
TFirst
,
TSecond
,
TThird
,
TFourth
,
TFifth
,
TReturn
>)
map
)(
deserializer
(
r
),
deserializer2
(
r
),
deserializer3
(
r
),
deserializer4
(
r
),
deserializer5
(
r
));
var
deserializer5
=
(
Func
<
IDataReader
,
TFifth
>)
info
.
OtherDeserializers
[
3
];
mapIt
=
r
=>
((
Func
<
TFirst
,
TSecond
,
TThird
,
TFourth
,
TFifth
,
TReturn
>)
map
)(
deserializer
(
r
),
deserializer2
(
r
),
deserializer3
(
r
),
deserializer4
(
r
),
deserializer5
(
r
));
#endif
}
}
}
}
if
(
mapIt
!=
null
)
if
(
mapIt
!=
null
)
{
bool
clean
=
true
;
try
{
bool
clean
=
true
;
try
{
while
(
reader
.
Read
())
{
clean
=
false
;
TReturn
next
=
mapIt
(
reader
);
clean
=
true
;
yield
return
next
;
}
}
finally
while
(
reader
.
Read
())
{
if
(!
clean
)
PurgeQueryCache
(
identity
);
clean
=
false
;
TReturn
next
=
mapIt
(
reader
);
clean
=
true
;
yield
return
next
;
}
}
finally
{
if
(!
clean
)
PurgeQueryCache
(
identity
);
}
}
}
finally
{
try
{
if
(
ownedReader
!=
null
)
{
ownedReader
.
Dispose
();
}
}
finally
{
if
(
ownedCommand
!=
null
)
{
ownedCommand
.
Dispose
();
}
}
}
}
...
...
@@ -1254,6 +1284,7 @@ public class GridReader : IDisposable
private
IDataReader
reader
;
private
IDbCommand
command
;
private
Identity
identity
;
internal
GridReader
(
IDbCommand
command
,
IDataReader
reader
,
Identity
identity
)
{
this
.
command
=
command
;
...
...
@@ -1279,7 +1310,63 @@ public IEnumerable<T> Read<T>()
return
ReadDeferred
(
gridIndex
,
deserializer
,
typedIdentity
);
}
// todo multimapping.
private
IEnumerable
<
TReturn
>
MultiReadInternal
<
TFirst
,
TSecond
,
TThird
,
TFourth
,
TFifth
,
TReturn
>(
object
func
,
string
splitOn
)
{
var
identity
=
this
.
identity
.
ForGrid
(
typeof
(
TReturn
),
new
Type
[]
{
typeof
(
TFirst
),
typeof
(
TSecond
),
typeof
(
TThird
),
typeof
(
TFourth
),
typeof
(
TFifth
)
},
gridIndex
);
try
{
foreach
(
var
r
in
SqlMapper
.
MultiMapImpl
<
TFirst
,
TSecond
,
DontMap
,
DontMap
,
DontMap
,
TReturn
>(
null
,
null
,
func
,
null
,
null
,
splitOn
,
null
,
null
,
reader
,
identity
))
{
yield
return
r
;
}
}
finally
{
NextResult
();
}
}
#if CSHARP30
public
IEnumerable
<
TReturn
>
Read
<
TFirst
,
TSecond
,
TReturn
>(
Func
<
TFirst
,
TSecond
,
TReturn
>
func
,
string
splitOn
)
#else
public
IEnumerable
<
TReturn
>
Read
<
TFirst
,
TSecond
,
TReturn
>(
Func
<
TFirst
,
TSecond
,
TReturn
>
func
,
string
splitOn
=
"id"
)
#endif
{
return
MultiReadInternal
<
TFirst
,
TSecond
,
DontMap
,
DontMap
,
DontMap
,
TReturn
>(
func
,
splitOn
);
}
#if CSHARP30
public
IEnumerable
<
TReturn
>
Read
<
TFirst
,
TSecond
,
TThird
,
TReturn
>(
Func
<
TFirst
,
TSecond
,
TThird
,
TReturn
>
func
,
string
splitOn
)
#else
public
IEnumerable
<
TReturn
>
Read
<
TFirst
,
TSecond
,
TThird
,
TReturn
>(
Func
<
TFirst
,
TSecond
,
TThird
,
TReturn
>
func
,
string
splitOn
=
"id"
)
#endif
{
return
MultiReadInternal
<
TFirst
,
TSecond
,
TThird
,
DontMap
,
DontMap
,
TReturn
>(
func
,
splitOn
);
}
#if CSHARP30
public
IEnumerable
<
TReturn
>
Read
<
TFirst
,
TSecond
,
TThird
,
TFourth
,
TReturn
>(
Func
<
TFirst
,
TSecond
,
TThird
,
TFourth
,
TReturn
>
func
,
string
splitOn
)
#else
public
IEnumerable
<
TReturn
>
Read
<
TFirst
,
TSecond
,
TThird
,
TFourth
,
TReturn
>(
Func
<
TFirst
,
TSecond
,
TThird
,
TFourth
,
TReturn
>
func
,
string
splitOn
=
"id"
)
#endif
{
return
MultiReadInternal
<
TFirst
,
TSecond
,
TThird
,
TFourth
,
DontMap
,
TReturn
>(
func
,
splitOn
);
}
#if !CSHARP30
public
IEnumerable
<
TReturn
>
Read
<
TFirst
,
TSecond
,
TThird
,
TFourth
,
TFifth
,
TReturn
>(
Func
<
TFirst
,
TSecond
,
TThird
,
TFourth
,
TFifth
,
TReturn
>
func
,
string
splitOn
=
"id"
)
{
return
MultiReadInternal
<
TFirst
,
TSecond
,
TThird
,
TFourth
,
TFifth
,
TReturn
>(
func
,
splitOn
);
}
#endif
private
IEnumerable
<
T
>
ReadDeferred
<
T
>(
int
index
,
Func
<
IDataReader
,
T
>
deserializer
,
Identity
typedIdentity
)
{
...
...
Tests/Tests.cs
浏览文件 @
49adbe1e
...
...
@@ -348,6 +348,51 @@ public void TestMultiMap()
}
public
void
TestMultiMapGridReader
()
{
var
createSql
=
@"
create table #Users (Id int, Name varchar(20))
create table #Posts (Id int, OwnerId int, Content varchar(20))
insert #Users values(99, 'Sam')
insert #Users values(2, 'I am')
insert #Posts values(1, 99, 'Sams Post1')
insert #Posts values(2, 99, 'Sams Post2')
insert #Posts values(3, null, 'no ones post')
"
;
connection
.
Execute
(
createSql
);
var
sql
=
@"select p.*, u.Id, u.Name + '0' Name from #Posts p
left join #Users u on u.Id = p.OwnerId
Order by p.Id
select p.*, u.Id, u.Name + '1' Name from #Posts p
left join #Users u on u.Id = p.OwnerId
Order by p.Id
"
;
var
grid
=
connection
.
QueryMultiple
(
sql
);
for
(
int
i
=
0
;
i
<
2
;
i
++)
{
var
data
=
grid
.
Read
<
Post
,
User
,
Post
>((
post
,
user
)
=>
{
post
.
Owner
=
user
;
return
post
;
}).
ToList
();
var
p
=
data
.
First
();
p
.
Content
.
IsEqualTo
(
"Sams Post1"
);
p
.
Id
.
IsEqualTo
(
1
);
p
.
Owner
.
Name
.
IsEqualTo
(
"Sam"
+
i
);
p
.
Owner
.
Id
.
IsEqualTo
(
99
);
data
[
2
].
Owner
.
IsNull
();
}
connection
.
Execute
(
"drop table #Users drop table #Posts"
);
}
public
void
TestMultiMapDynamic
()
{
var
createSql
=
@"
...
...
@@ -810,6 +855,7 @@ public void ParentChildIdentityAssociations()
parents
[
3
].
Children
.
Select
(
c
=>
c
.
Id
).
SequenceEqual
(
new
[]
{
5
}).
IsTrue
();
}
/* TODO:
*
public void TestMagicParam()
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录