Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Dapper
提交
db08e25d
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,发现更多精彩内容 >>
提交
db08e25d
编写于
4月 26, 2011
作者:
S
Sam Saffron
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
completed multi map implementation
上级
bc344d0c
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
169 addition
and
42 deletion
+169
-42
Dapper/SqlMapper.cs
Dapper/SqlMapper.cs
+130
-41
Tests/Tests.cs
Tests/Tests.cs
+39
-1
未找到文件。
Dapper/SqlMapper.cs
浏览文件 @
db08e25d
...
...
@@ -21,7 +21,7 @@ public static class SqlMapper
class
CacheInfo
{
public
object
Deserializer
{
get
;
set
;
}
public
object
Deserializer2
{
get
;
set
;
}
public
object
[]
OtherDeserializers
{
get
;
set
;
}
public
Action
<
IDbCommand
,
object
>
ParamReader
{
get
;
set
;
}
}
...
...
@@ -94,19 +94,25 @@ private class Identity : IEquatable<Identity>
public
Type
Type2
{
get
{
return
Type2
;
}
}
public
string
Sql
{
get
{
return
sql
;
}
}
public
Type
ParametersType
{
get
{
return
ParametersType
;
}
}
internal
Identity
(
string
sql
,
IDbConnection
cnn
,
Type
type
,
Type
parametersType
,
Type
type2
=
null
)
internal
Identity
(
string
sql
,
IDbConnection
cnn
,
Type
type
,
Type
parametersType
,
Type
[]
otherTypes
=
null
)
{
this
.
sql
=
sql
;
this
.
connectionString
=
cnn
.
ConnectionString
;
this
.
type
=
type
;
this
.
parametersType
=
parametersType
;
this
.
type2
=
type2
;
this
.
otherTypes
=
otherTypes
;
unchecked
{
hashCode
=
17
;
// we *know* we are using this in a dictionary, so pre-compute this
hashCode
=
hashCode
*
23
+
(
sql
==
null
?
0
:
sql
.
GetHashCode
());
hashCode
=
hashCode
*
23
+
(
type
==
null
?
0
:
type
.
GetHashCode
());
hashCode
=
hashCode
*
23
+
(
type2
==
null
?
0
:
type2
.
GetHashCode
());
if
(
otherTypes
!=
null
)
{
for
(
int
i
=
0
;
i
<
otherTypes
.
Length
;
i
++)
{
hashCode
=
hashCode
*
23
+
(
otherTypes
[
i
]
==
null
?
0
:
otherTypes
[
i
].
GetHashCode
());
}
}
hashCode
=
hashCode
*
23
+
(
connectionString
==
null
?
0
:
connectionString
.
GetHashCode
());
hashCode
=
hashCode
*
23
+
(
parametersType
==
null
?
0
:
parametersType
.
GetHashCode
());
}
...
...
@@ -118,7 +124,7 @@ public override bool Equals(object obj)
private
readonly
string
sql
;
private
readonly
int
hashCode
;
private
readonly
Type
type
;
private
readonly
Type
type2
;
private
readonly
Type
[]
otherTypes
;
private
readonly
string
connectionString
;
private
readonly
Type
parametersType
;
public
override
int
GetHashCode
()
...
...
@@ -169,7 +175,6 @@ public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object
}
}
/// <summary>
/// Return a typed list of objects, reader is closed after the call
/// </summary>
...
...
@@ -199,9 +204,9 @@ private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sq
}
/// <summary>
///
///
Maps a query to objects
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="T">
The return type
</typeparam>
/// <typeparam name="U"></typeparam>
/// <param name="cnn"></param>
/// <param name="sql"></param>
...
...
@@ -212,7 +217,28 @@ private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sq
/// <returns></returns>
public
static
IEnumerable
<
T
>
Query
<
T
,
U
>(
this
IDbConnection
cnn
,
string
sql
,
Action
<
T
,
U
>
map
,
object
param
=
null
,
IDbTransaction
transaction
=
null
,
bool
buffered
=
true
,
string
splitOn
=
"Id"
)
{
var
identity
=
new
Identity
(
sql
,
cnn
,
typeof
(
T
),
param
==
null
?
null
:
param
.
GetType
());
return
MultiMap
<
T
,
U
,
DontMap
,
DontMap
,
DontMap
>(
cnn
,
sql
,
map
,
param
,
transaction
,
buffered
,
splitOn
);
}
public
static
IEnumerable
<
T
>
Query
<
T
,
U
,
V
>(
this
IDbConnection
cnn
,
string
sql
,
Action
<
T
,
U
,
V
>
map
,
object
param
=
null
,
IDbTransaction
transaction
=
null
,
bool
buffered
=
true
,
string
splitOn
=
"Id"
)
{
return
MultiMap
<
T
,
U
,
V
,
DontMap
,
DontMap
>(
cnn
,
sql
,
map
,
param
,
transaction
,
buffered
,
splitOn
);
}
public
static
IEnumerable
<
T
>
Query
<
T
,
U
,
V
,
Z
>(
this
IDbConnection
cnn
,
string
sql
,
Action
<
T
,
U
,
V
,
Z
>
map
,
object
param
=
null
,
IDbTransaction
transaction
=
null
,
bool
buffered
=
true
,
string
splitOn
=
"Id"
)
{
return
MultiMap
<
T
,
U
,
V
,
Z
,
DontMap
>(
cnn
,
sql
,
map
,
param
,
transaction
,
buffered
,
splitOn
);
}
public
static
IEnumerable
<
T
>
Query
<
T
,
U
,
V
,
Z
,
X
>(
this
IDbConnection
cnn
,
string
sql
,
Action
<
T
,
U
,
V
,
Z
,
X
>
map
,
object
param
=
null
,
IDbTransaction
transaction
=
null
,
bool
buffered
=
true
,
string
splitOn
=
"Id"
)
{
return
MultiMap
<
T
,
U
,
V
,
Z
,
X
>(
cnn
,
sql
,
map
,
param
,
transaction
,
buffered
,
splitOn
);
}
class
DontMap
{}
static
IEnumerable
<
T
>
MultiMap
<
T
,
U
,
V
,
Z
,
X
>(
this
IDbConnection
cnn
,
string
sql
,
object
map
,
object
param
=
null
,
IDbTransaction
transaction
=
null
,
bool
buffered
=
true
,
string
splitOn
=
"Id"
)
{
var
identity
=
new
Identity
(
sql
,
cnn
,
typeof
(
T
),
param
==
null
?
null
:
param
.
GetType
(),
otherTypes
:
new
Type
[]
{
typeof
(
T
),
typeof
(
U
),
typeof
(
V
),
typeof
(
Z
),
typeof
(
X
)
});
var
info
=
GetCacheInfo
(
param
,
identity
);
using
(
var
cmd
=
SetupCommand
(
cnn
,
transaction
,
sql
,
info
.
ParamReader
,
param
))
...
...
@@ -221,47 +247,115 @@ private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sq
{
if
(
info
.
Deserializer
==
null
)
{
int
star
t
=
0
;
int
length
=
-
1
;
var
spli
t
=
0
;
int
current
=
0
;
for
(
length
=
1
;
length
<
reader
.
FieldCount
;
length
++)
Func
<
int
>
nextSplit
=
()
=>
{
if
(
reader
.
GetName
(
length
)
==
splitOn
)
int
pos
;
for
(
pos
=
current
+
1
;
pos
<
reader
.
FieldCount
;
pos
++)
{
break
;
if
(
reader
.
GetName
(
pos
)
==
splitOn
)
{
break
;
}
}
current
=
pos
;
return
pos
;
};
List
<
object
>
otherDeserializer
=
new
List
<
object
>();
split
=
nextSplit
();
info
.
Deserializer
=
GetDeserializer
<
T
>(
identity
,
reader
,
0
,
split
);
if
(
typeof
(
U
)
!=
typeof
(
DontMap
))
{
var
next
=
nextSplit
();
otherDeserializer
.
Add
(
GetDeserializer
<
U
>(
identity
,
reader
,
split
,
next
-
split
,
returnNullIfFirstMissing
:
true
));
split
=
next
;
}
if
(
typeof
(
V
)
!=
typeof
(
DontMap
))
{
var
next
=
nextSplit
();
otherDeserializer
.
Add
(
GetDeserializer
<
V
>(
identity
,
reader
,
split
,
next
-
split
,
returnNullIfFirstMissing
:
true
));
split
=
next
;
}
if
(
typeof
(
Z
)
!=
typeof
(
DontMap
))
{
var
next
=
nextSplit
();
otherDeserializer
.
Add
(
GetDeserializer
<
Z
>(
identity
,
reader
,
split
,
next
-
split
,
returnNullIfFirstMissing
:
true
));
split
=
next
;
}
if
(
typeof
(
X
)
!=
typeof
(
DontMap
))
{
var
next
=
nextSplit
();
otherDeserializer
.
Add
(
GetDeserializer
<
X
>(
identity
,
reader
,
split
,
next
-
split
,
returnNullIfFirstMissing
:
true
));
}
// dynamic comes back as object ...
if
(
typeof
(
T
)
==
typeof
(
object
))
{
info
.
Deserializer
=
GetDeserializer
<
ExpandoObject
>(
identity
,
reader
,
start
,
length
);
}
else
{
info
.
Deserializer
=
GetDeserializer
<
T
>(
identity
,
reader
,
start
,
length
);
info
.
OtherDeserializers
=
otherDeserializer
.
ToArray
();
queryCache
[
identity
]
=
info
;
}
if
(
typeof
(
U
)
==
typeof
(
object
))
var
deserializer
=
(
Func
<
IDataReader
,
T
>)
info
.
Deserializer
;
var
deserializer2
=
(
Func
<
IDataReader
,
U
>)
info
.
OtherDeserializers
[
0
];
Func
<
IDataReader
,
T
>
mapIt
=
null
;
if
(
info
.
OtherDeserializers
.
Length
==
1
)
{
info
.
Deserializer2
=
GetDeserializer
<
ExpandoObject
>(
identity
,
reader
,
start
+
length
,
returnNullIfFirstMissing
:
true
);
mapIt
=
r
=>
{
var
tmp
=
deserializer
(
r
);
((
Action
<
T
,
U
>)
map
)(
tmp
,
deserializer2
(
r
));
return
tmp
;
};
}
else
if
(
info
.
OtherDeserializers
.
Length
>
1
)
{
info
.
Deserializer2
=
GetDeserializer
<
U
>(
identity
,
reader
,
start
+
length
,
returnNullIfFirstMissing
:
true
);
}
var
deserializer3
=
(
Func
<
IDataReader
,
V
>)
info
.
OtherDeserializers
[
1
];
queryCache
[
identity
]
=
info
;
}
if
(
info
.
OtherDeserializers
.
Length
==
2
)
{
mapIt
=
r
=>
{
var
tmp
=
deserializer
(
r
);
((
Action
<
T
,
U
,
V
>)
map
)(
tmp
,
deserializer2
(
r
),
deserializer3
(
r
));
return
tmp
;
};
}
if
(
info
.
OtherDeserializers
.
Length
>
2
)
{
var
deserializer4
=
(
Func
<
IDataReader
,
Z
>)
info
.
OtherDeserializers
[
2
];
if
(
info
.
OtherDeserializers
.
Length
==
3
)
{
mapIt
=
r
=>
{
var
tmp
=
deserializer
(
r
);
((
Action
<
T
,
U
,
V
,
Z
>)
map
)(
tmp
,
deserializer2
(
r
),
deserializer3
(
r
),
deserializer4
(
r
));
return
tmp
;
};
}
var
deserializer
=
(
Func
<
IDataReader
,
T
>)
info
.
Deserializer
;
var
deserializer2
=
(
Func
<
IDataReader
,
U
>)
info
.
Deserializer2
;
if
(
info
.
OtherDeserializers
.
Length
>
3
)
{
var
deserializer5
=
(
Func
<
IDataReader
,
X
>)
info
.
OtherDeserializers
[
3
];
mapIt
=
r
=>
{
var
tmp
=
deserializer
(
r
);
((
Action
<
T
,
U
,
V
,
Z
,
X
>)
map
)(
tmp
,
deserializer2
(
r
),
deserializer3
(
r
),
deserializer4
(
r
),
deserializer5
(
r
));
return
tmp
;
};
}
}
}
while
(
reader
.
Read
())
{
var
tmp
=
deserializer
(
reader
);
map
(
tmp
,
deserializer2
(
reader
));
yield
return
tmp
;
yield
return
mapIt
(
reader
);
}
}
}
...
...
@@ -281,17 +375,12 @@ private static CacheInfo GetCacheInfo(object param, Identity identity)
return
info
;
}
class
DynamicStub
{
public
static
Type
Type
=
typeof
(
DynamicStub
);
}
static
Func
<
IDataReader
,
T
>
GetDeserializer
<
T
>(
Identity
identity
,
IDataReader
reader
,
int
startBound
=
0
,
int
length
=
-
1
,
bool
returnNullIfFirstMissing
=
false
)
{
object
oDeserializer
;
if
(
typeof
(
T
)
==
DynamicStub
.
Type
||
typeof
(
T
)
==
typeof
(
ExpandoObject
))
// dynamic is passed in as Object ... by c# design
if
(
typeof
(
T
)
==
typeof
(
object
)
||
typeof
(
T
)
==
typeof
(
ExpandoObject
))
{
oDeserializer
=
GetDynamicDeserializer
(
reader
,
startBound
,
length
,
returnNullIfFirstMissing
);
}
...
...
Tests/Tests.cs
浏览文件 @
db08e25d
...
...
@@ -6,7 +6,7 @@
namespace
SqlMapper
{
static
class
TestAssertions
static
class
Assert
{
public
static
void
IsEqualTo
<
T
>(
this
T
obj
,
T
other
)
...
...
@@ -320,6 +320,44 @@ public void TestMultiMapDynamic()
connection
.
Execute
(
"drop table #Users drop table #Posts"
);
}
public
void
TestMultiMappingVariations
()
{
var
sql
=
"select 1 as Id, 'a' as Content, 2 as Id, 'b' as Content, 3 as Id, 'c' as Content, 4 as Id, 'd' as Content, 5 as Id, 'e' as Content"
;
var
mapped
=
connection
.
Query
<
dynamic
,
dynamic
,
dynamic
>(
sql
,
(
a
,
b
,
c
)
=>
{
a
.
B
=
b
;
a
.
C
=
c
;
}).
First
();
Assert
.
IsEqualTo
(
mapped
.
Id
,
1
);
Assert
.
IsEqualTo
(
mapped
.
Content
,
"a"
);
Assert
.
IsEqualTo
(
mapped
.
B
.
Id
,
2
);
Assert
.
IsEqualTo
(
mapped
.
B
.
Content
,
"b"
);
Assert
.
IsEqualTo
(
mapped
.
C
.
Id
,
3
);
Assert
.
IsEqualTo
(
mapped
.
C
.
Content
,
"c"
);
mapped
=
connection
.
Query
<
dynamic
,
dynamic
,
dynamic
,
dynamic
>(
sql
,
(
a
,
b
,
c
,
d
)
=>
{
a
.
B
=
b
;
a
.
C
=
c
;
a
.
C
.
D
=
d
;
}).
First
();
Assert
.
IsEqualTo
(
mapped
.
Id
,
1
);
Assert
.
IsEqualTo
(
mapped
.
Content
,
"a"
);
Assert
.
IsEqualTo
(
mapped
.
B
.
Id
,
2
);
Assert
.
IsEqualTo
(
mapped
.
B
.
Content
,
"b"
);
Assert
.
IsEqualTo
(
mapped
.
C
.
Id
,
3
);
Assert
.
IsEqualTo
(
mapped
.
C
.
Content
,
"c"
);
Assert
.
IsEqualTo
(
mapped
.
C
.
D
.
Id
,
4
);
Assert
.
IsEqualTo
(
mapped
.
C
.
D
.
Content
,
"d"
);
mapped
=
connection
.
Query
<
dynamic
,
dynamic
,
dynamic
,
dynamic
,
dynamic
>(
sql
,
(
a
,
b
,
c
,
d
,
e
)
=>
{
a
.
B
=
b
;
a
.
C
=
c
;
a
.
C
.
D
=
d
;
a
.
E
=
e
;
}).
First
();
Assert
.
IsEqualTo
(
mapped
.
Id
,
1
);
Assert
.
IsEqualTo
(
mapped
.
Content
,
"a"
);
Assert
.
IsEqualTo
(
mapped
.
B
.
Id
,
2
);
Assert
.
IsEqualTo
(
mapped
.
B
.
Content
,
"b"
);
Assert
.
IsEqualTo
(
mapped
.
C
.
Id
,
3
);
Assert
.
IsEqualTo
(
mapped
.
C
.
Content
,
"c"
);
Assert
.
IsEqualTo
(
mapped
.
C
.
D
.
Id
,
4
);
Assert
.
IsEqualTo
(
mapped
.
C
.
D
.
Content
,
"d"
);
Assert
.
IsEqualTo
(
mapped
.
E
.
Id
,
5
);
Assert
.
IsEqualTo
(
mapped
.
E
.
Content
,
"e"
);
}
class
InheritanceTest1
{
public
string
Base1
{
get
;
set
;
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录