Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
D
Dapper
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
tsai
Dapper
Commits
db08e25d
Commit
db08e25d
authored
Apr 26, 2011
by
Sam Saffron
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
completed multi map implementation
parent
bc344d0c
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
169 additions
and
42 deletions
+169
-42
SqlMapper.cs
Dapper/SqlMapper.cs
+130
-41
Tests.cs
Tests/Tests.cs
+39
-1
No files found.
Dapper/SqlMapper.cs
View file @
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
View file @
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
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment