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
9d7e6589
Commit
9d7e6589
authored
Apr 26, 2011
by
Sam Saffron
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dynamic multi deserialization for extra awesome
bug fix around null objects
parent
20b9ec35
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
92 additions
and
13 deletions
+92
-13
SqlMapper.cs
Dapper/SqlMapper.cs
+51
-12
Tests.cs
Tests/Tests.cs
+41
-1
No files found.
Dapper/SqlMapper.cs
View file @
9d7e6589
...
@@ -227,8 +227,25 @@ private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sq
...
@@ -227,8 +227,25 @@ private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sq
}
}
}
}
info
.
Deserializer
=
GetDeserializer
<
T
>(
identity
,
reader
,
start
,
length
);
// dynamic comes back as object ...
info
.
Deserializer2
=
GetDeserializer
<
U
>(
identity
,
reader
,
start
+
length
);
if
(
typeof
(
T
)
==
typeof
(
object
))
{
info
.
Deserializer
=
GetDeserializer
<
ExpandoObject
>(
identity
,
reader
,
start
,
length
);
}
else
{
info
.
Deserializer
=
GetDeserializer
<
T
>(
identity
,
reader
,
start
,
length
);
}
if
(
typeof
(
U
)
==
typeof
(
object
))
{
info
.
Deserializer2
=
GetDeserializer
<
ExpandoObject
>(
identity
,
reader
,
start
+
length
,
returnNullIfFirstMissing
:
true
);
}
else
{
info
.
Deserializer2
=
GetDeserializer
<
U
>(
identity
,
reader
,
start
+
length
,
returnNullIfFirstMissing
:
true
);
}
queryCache
[
identity
]
=
info
;
queryCache
[
identity
]
=
info
;
}
}
...
@@ -259,22 +276,22 @@ private static CacheInfo GetCacheInfo(object param, Identity identity)
...
@@ -259,22 +276,22 @@ private static CacheInfo GetCacheInfo(object param, Identity identity)
}
}
static
class
DynamicStub
class
DynamicStub
{
{
public
static
Type
Type
=
typeof
(
DynamicStub
);
public
static
Type
Type
=
typeof
(
DynamicStub
);
}
}
static
Func
<
IDataReader
,
T
>
GetDeserializer
<
T
>(
Identity
identity
,
IDataReader
reader
,
int
startBound
=
0
,
int
length
=
-
1
)
static
Func
<
IDataReader
,
T
>
GetDeserializer
<
T
>(
Identity
identity
,
IDataReader
reader
,
int
startBound
=
0
,
int
length
=
-
1
,
bool
returnNullIfFirstMissing
=
false
)
{
{
object
oDeserializer
;
object
oDeserializer
;
if
(
typeof
(
T
)
==
DynamicStub
.
Type
||
typeof
(
T
)
==
typeof
(
ExpandoObject
))
if
(
typeof
(
T
)
==
DynamicStub
.
Type
||
typeof
(
T
)
==
typeof
(
ExpandoObject
))
{
{
oDeserializer
=
GetDynamicDeserializer
(
reader
);
oDeserializer
=
GetDynamicDeserializer
(
reader
,
startBound
,
length
,
returnNullIfFirstMissing
);
}
}
else
if
(
typeof
(
T
).
IsClass
&&
typeof
(
T
)
!=
typeof
(
string
))
else
if
(
typeof
(
T
).
IsClass
&&
typeof
(
T
)
!=
typeof
(
string
))
{
{
oDeserializer
=
GetClassDeserializer
<
T
>(
reader
,
startBound
,
length
);
oDeserializer
=
GetClassDeserializer
<
T
>(
reader
,
startBound
,
length
,
returnNullIfFirstMissing
:
returnNullIfFirstMissing
);
}
}
else
else
{
{
...
@@ -285,10 +302,16 @@ static class DynamicStub
...
@@ -285,10 +302,16 @@ static class DynamicStub
return
deserializer
;
return
deserializer
;
}
}
private
static
object
GetDynamicDeserializer
(
IDataReader
reader
)
private
static
object
GetDynamicDeserializer
(
IDataReader
reader
,
int
startBound
=
0
,
int
length
=
-
1
,
bool
returnNullIfFirstMissing
=
false
)
{
{
List
<
string
>
colNames
=
new
List
<
string
>();
List
<
string
>
colNames
=
new
List
<
string
>();
for
(
int
i
=
0
;
i
<
reader
.
FieldCount
;
i
++)
if
(
length
==
-
1
)
{
length
=
reader
.
FieldCount
-
startBound
;
}
for
(
int
i
=
startBound
;
i
<
startBound
+
length
;
i
++)
{
{
colNames
.
Add
(
reader
.
GetName
(
i
));
colNames
.
Add
(
reader
.
GetName
(
i
));
}
}
...
@@ -297,12 +320,19 @@ private static object GetDynamicDeserializer(IDataReader reader)
...
@@ -297,12 +320,19 @@ private static object GetDynamicDeserializer(IDataReader reader)
r
=>
r
=>
{
{
IDictionary
<
string
,
object
>
row
=
new
ExpandoObject
();
IDictionary
<
string
,
object
>
row
=
new
ExpandoObject
();
int
i
=
0
;
int
i
=
startBound
;
bool
first
=
true
;
foreach
(
var
colName
in
colNames
)
foreach
(
var
colName
in
colNames
)
{
{
var
tmp
=
r
.
GetValue
(
i
);
var
tmp
=
r
.
GetValue
(
i
);
row
[
colName
]
=
tmp
==
DBNull
.
Value
?
null
:
tmp
;
tmp
=
tmp
==
DBNull
.
Value
?
null
:
tmp
;
row
[
colName
]
=
tmp
;
if
(
returnNullIfFirstMissing
&&
first
&&
tmp
==
null
)
{
return
null
;
}
i
++;
i
++;
first
=
false
;
}
}
return
(
ExpandoObject
)
row
;
return
(
ExpandoObject
)
row
;
};
};
...
@@ -521,7 +551,7 @@ private static object GetStructDeserializer<T>(IDataReader reader)
...
@@ -521,7 +551,7 @@ private static object GetStructDeserializer<T>(IDataReader reader)
return
deserializer
;
return
deserializer
;
}
}
public
static
Func
<
IDataReader
,
T
>
GetClassDeserializer
<
T
>(
IDataReader
reader
,
int
startBound
=
0
,
int
length
=
-
1
)
public
static
Func
<
IDataReader
,
T
>
GetClassDeserializer
<
T
>(
IDataReader
reader
,
int
startBound
=
0
,
int
length
=
-
1
,
bool
returnNullIfFirstMissing
=
false
)
{
{
DynamicMethod
dm
=
new
DynamicMethod
(
"Deserialize"
+
Guid
.
NewGuid
().
ToString
(),
typeof
(
T
),
new
Type
[]
{
typeof
(
IDataReader
)
},
true
);
DynamicMethod
dm
=
new
DynamicMethod
(
"Deserialize"
+
Guid
.
NewGuid
().
ToString
(),
typeof
(
T
),
new
Type
[]
{
typeof
(
IDataReader
)
},
true
);
...
@@ -560,6 +590,7 @@ private static object GetStructDeserializer<T>(IDataReader reader)
...
@@ -560,6 +590,7 @@ private static object GetStructDeserializer<T>(IDataReader reader)
// stack is empty
// stack is empty
il
.
Emit
(
OpCodes
.
Newobj
,
typeof
(
T
).
GetConstructor
(
Type
.
EmptyTypes
));
// stack is now [target]
il
.
Emit
(
OpCodes
.
Newobj
,
typeof
(
T
).
GetConstructor
(
Type
.
EmptyTypes
));
// stack is now [target]
bool
first
=
true
;
foreach
(
var
item
in
setters
)
foreach
(
var
item
in
setters
)
{
{
if
(
item
.
Info
!=
null
)
if
(
item
.
Info
!=
null
)
...
@@ -581,13 +612,21 @@ private static object GetStructDeserializer<T>(IDataReader reader)
...
@@ -581,13 +612,21 @@ private static object GetStructDeserializer<T>(IDataReader reader)
il
.
Emit
(
OpCodes
.
Callvirt
,
item
.
Info
.
Setter
);
// stack is now [target]
il
.
Emit
(
OpCodes
.
Callvirt
,
item
.
Info
.
Setter
);
// stack is now [target]
il
.
Emit
(
OpCodes
.
Br_S
,
finishLabel
);
// stack is now [target]
il
.
Emit
(
OpCodes
.
Br_S
,
finishLabel
);
// stack is now [target]
il
.
MarkLabel
(
isDbNullLabel
);
// incoming stack: [target][target][value]
il
.
MarkLabel
(
isDbNullLabel
);
// incoming stack: [target][target][value]
il
.
Emit
(
OpCodes
.
Pop
);
// stack is now [target][target]
il
.
Emit
(
OpCodes
.
Pop
);
// stack is now [target][target]
il
.
Emit
(
OpCodes
.
Pop
);
// stack is now [target]
il
.
Emit
(
OpCodes
.
Pop
);
// stack is now [target]
if
(
first
&&
returnNullIfFirstMissing
)
{
il
.
Emit
(
OpCodes
.
Pop
);
il
.
Emit
(
OpCodes
.
Ldnull
);
// stack is now [null]
il
.
Emit
(
OpCodes
.
Ret
);
}
il
.
MarkLabel
(
finishLabel
);
il
.
MarkLabel
(
finishLabel
);
}
}
first
=
false
;
index
+=
1
;
index
+=
1
;
}
}
il
.
Emit
(
OpCodes
.
Ret
);
// stack is empty
il
.
Emit
(
OpCodes
.
Ret
);
// stack is empty
...
...
Tests/Tests.cs
View file @
9d7e6589
...
@@ -269,13 +269,53 @@ public void TestMultiMap()
...
@@ -269,13 +269,53 @@ public void TestMultiMap()
left join #Users u on u.Id = p.OwnerId
left join #Users u on u.Id = p.OwnerId
Order by p.Id"
;
Order by p.Id"
;
var
data
=
connection
.
Query
<
Post
,
User
>(
sql
,
(
post
,
user
)
=>
{
post
.
Owner
=
user
;
});
var
data
=
connection
.
Query
<
Post
,
User
>(
sql
,
(
post
,
user
)
=>
{
post
.
Owner
=
user
;
})
.
ToList
()
;
var
p
=
data
.
First
();
var
p
=
data
.
First
();
p
.
Content
.
IsEqualTo
(
"Sams Post1"
);
p
.
Content
.
IsEqualTo
(
"Sams Post1"
);
p
.
Id
.
IsEqualTo
(
1
);
p
.
Id
.
IsEqualTo
(
1
);
p
.
Owner
.
Name
.
IsEqualTo
(
"Sam"
);
p
.
Owner
.
Name
.
IsEqualTo
(
"Sam"
);
p
.
Owner
.
Id
.
IsEqualTo
(
99
);
p
.
Owner
.
Id
.
IsEqualTo
(
99
);
data
[
2
].
Owner
.
IsNull
();
connection
.
Execute
(
"drop table #Users drop table #Posts"
);
}
public
void
TestMultiMapDynamic
()
{
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 * from #Posts p
left join #Users u on u.Id = p.OwnerId
Order by p.Id"
;
var
data
=
connection
.
Query
<
dynamic
,
dynamic
>(
sql
,
(
post
,
user
)
=>
{
post
.
Owner
=
user
;
}).
ToList
();
var
p
=
data
.
First
();
// hairy extension method support for dynamics
((
string
)
p
.
Content
).
IsEqualTo
(
"Sams Post1"
);
((
int
)
p
.
Id
).
IsEqualTo
(
1
);
((
string
)
p
.
Owner
.
Name
).
IsEqualTo
(
"Sam"
);
((
int
)
p
.
Owner
.
Id
).
IsEqualTo
(
99
);
((
object
)
data
[
2
].
Owner
).
IsNull
();
connection
.
Execute
(
"drop table #Users drop table #Posts"
);
}
}
}
}
}
}
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