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
db1c00a8
Commit
db1c00a8
authored
Jun 14, 2011
by
Sam Saffron
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added support for a multi mapping grid reader
parent
d9ef0084
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
227 additions
and
94 deletions
+227
-94
SqlMapper.cs
Dapper/SqlMapper.cs
+181
-94
Tests.cs
Tests/Tests.cs
+46
-0
No files found.
Dapper/SqlMapper.cs
View file @
db1c00a8
...
...
@@ -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
View file @
db1c00a8
...
...
@@ -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()
...
...
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