-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSqlMapper.IDataReader.cs
153 lines (148 loc) · 6.91 KB
/
SqlMapper.IDataReader.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
using System;
using System.Collections.Generic;
using System.Data;
namespace Dapper
{
public static partial class SqlMapper
{
/// <summary>
/// Parses a data reader to a sequence of data of the supplied type. Used for deserializing a reader without a connection, etc.
/// </summary>
/// <typeparam name="T">The type to parse from the <paramref name="reader"/>.</typeparam>
/// <param name="reader">The data reader to parse results from.</param>
public static IEnumerable<T> Parse<T>(this IDataReader reader)
{
if (reader.Read())
{
var effectiveType = typeof(T);
var deser = GetDeserializer(effectiveType, reader, 0, -1, false);
var convertToType = Nullable.GetUnderlyingType(effectiveType) ?? effectiveType;
do
{
object val = deser(reader);
if (val == null || val is T)
{
yield return (T)val;
}
else
{
yield return (T)Convert.ChangeType(val, convertToType, System.Globalization.CultureInfo.InvariantCulture);
}
} while (reader.Read());
}
}
/// <summary>
/// Parses a data reader to a sequence of data of the supplied type (as object). Used for deserializing a reader without a connection, etc.
/// </summary>
/// <param name="reader">The data reader to parse results from.</param>
/// <param name="type">The type to parse from the <paramref name="reader"/>.</param>
public static IEnumerable<object> Parse(this IDataReader reader, Type type)
{
if (reader.Read())
{
var deser = GetDeserializer(type, reader, 0, -1, false);
do
{
yield return deser(reader);
} while (reader.Read());
}
}
/// <summary>
/// Parses a data reader to a sequence of dynamic. Used for deserializing a reader without a connection, etc.
/// </summary>
/// <param name="reader">The data reader to parse results from.</param>
public static IEnumerable<dynamic> Parse(this IDataReader reader)
{
if (reader.Read())
{
var deser = GetDapperRowDeserializer(reader, 0, -1, false);
do
{
yield return deser(reader);
} while (reader.Read());
}
}
/// <summary>
/// Gets the row parser for a specific row on a data reader. This allows for type switching every row based on, for example, a TypeId column.
/// You could return a collection of the base type but have each more specific.
/// </summary>
/// <param name="reader">The data reader to get the parser for the current row from</param>
/// <param name="type">The type to get the parser for</param>
/// <param name="startIndex">The start column index of the object (default 0)</param>
/// <param name="length">The length of columns to read (default -1 = all fields following startIndex)</param>
/// <param name="returnNullIfFirstMissing">Return null if we can't find the first column? (default false)</param>
/// <returns>A parser for this specific object from this row.</returns>
public static Func<IDataReader, object> GetRowParser(this IDataReader reader, Type type,
int startIndex = 0, int length = -1, bool returnNullIfFirstMissing = false)
{
return GetDeserializer(type, reader, startIndex, length, returnNullIfFirstMissing);
}
/// <summary>
/// Gets the row parser for a specific row on a data reader. This allows for type switching every row based on, for example, a TypeId column.
/// You could return a collection of the base type but have each more specific.
/// </summary>
/// <typeparam name="T">The type of results to return.</typeparam>
/// <param name="reader">The data reader to get the parser for the current row from.</param>
/// <param name="concreteType">The type to get the parser for.</param>
/// <param name="startIndex">The start column index of the object (default: 0).</param>
/// <param name="length">The length of columns to read (default: -1 = all fields following startIndex).</param>
/// <param name="returnNullIfFirstMissing">Return null if we can't find the first column? (default: false).</param>
/// <returns>A parser for this specific object from this row.</returns>
/// <example>
/// var result = new List<BaseType>();
/// using (var reader = connection.ExecuteReader(@"
/// select 'abc' as Name, 1 as Type, 3.0 as Value
/// union all
/// select 'def' as Name, 2 as Type, 4.0 as Value"))
/// {
/// if (reader.Read())
/// {
/// var toFoo = reader.GetRowParser<BaseType>(typeof(Foo));
/// var toBar = reader.GetRowParser<BaseType>(typeof(Bar));
/// var col = reader.GetOrdinal("Type");
/// do
/// {
/// switch (reader.GetInt32(col))
/// {
/// case 1:
/// result.Add(toFoo(reader));
/// break;
/// case 2:
/// result.Add(toBar(reader));
/// break;
/// }
/// } while (reader.Read());
/// }
/// }
///
/// abstract class BaseType
/// {
/// public abstract int Type { get; }
/// }
/// class Foo : BaseType
/// {
/// public string Name { get; set; }
/// public override int Type => 1;
/// }
/// class Bar : BaseType
/// {
/// public float Value { get; set; }
/// public override int Type => 2;
/// }
/// </example>
public static Func<IDataReader, T> GetRowParser<T>(this IDataReader reader, Type concreteType = null,
int startIndex = 0, int length = -1, bool returnNullIfFirstMissing = false)
{
concreteType ??= typeof(T);
var func = GetDeserializer(concreteType, reader, startIndex, length, returnNullIfFirstMissing);
if (concreteType.IsValueType)
{
return _ => (T)func(_);
}
else
{
return (Func<IDataReader, T>)(Delegate)func;
}
}
}
}