Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit fa188dc

Browse files
committed
Rewrite PopulateWithSqlReader to better utilize field cache and reader.GetValues() for improved perf
1 parent d6ee33e commit fa188dc

8 files changed

+245
-263
lines changed

src/ServiceStack.OrmLite/Async/OrmLiteUtilExtensionsAsync.cs

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,93 +18,91 @@ public static T CreateInstance<T>()
1818
return (T)ReflectionExtensions.CreateInstance<T>();
1919
}
2020

21-
public static Task<T> ConvertToAsync<T>(this IDataReader dataReader, IOrmLiteDialectProvider dialectProvider, CancellationToken token)
21+
public static Task<T> ConvertToAsync<T>(this IDataReader reader, IOrmLiteDialectProvider dialectProvider, CancellationToken token)
2222
{
23-
var fieldDefs = ModelDefinition<T>.Definition.AllFieldDefinitionsArray;
24-
return dialectProvider.ReaderRead(dataReader, () =>
23+
var indexCache = reader.GetIndexFieldsCache(ModelDefinition<T>.Definition, dialectProvider);
24+
var values = new object[reader.FieldCount];
25+
return dialectProvider.ReaderRead(reader, () =>
2526
{
2627
var row = CreateInstance<T>();
27-
var indexCache = dataReader.GetIndexFieldsCache(ModelDefinition<T>.Definition);
28-
row.PopulateWithSqlReader(dialectProvider, dataReader, fieldDefs, indexCache);
28+
row.PopulateWithSqlReader(dialectProvider, reader, indexCache, values);
2929
return row;
3030
}, token).Then(t => {
31-
dataReader.Dispose();
31+
reader.Dispose();
3232
return t;
3333
});
3434
}
3535

36-
public static Task<List<T>> ConvertToListAsync<T>(this IDataReader dataReader, IOrmLiteDialectProvider dialectProvider, CancellationToken token)
36+
public static Task<List<T>> ConvertToListAsync<T>(this IDataReader reader, IOrmLiteDialectProvider dialectProvider, CancellationToken token)
3737
{
38-
var fieldDefs = ModelDefinition<T>.Definition.AllFieldDefinitionsArray;
39-
var indexCache = dataReader.GetIndexFieldsCache(ModelDefinition<T>.Definition);
38+
var indexCache = reader.GetIndexFieldsCache(ModelDefinition<T>.Definition, dialectProvider);
39+
var values = new object[reader.FieldCount];
4040
var isObjectList = typeof(T) == typeof(List<object>);
4141
var isObjectDict = typeof(T) == typeof(Dictionary<string,object>);
4242

43-
return dialectProvider.ReaderEach(dataReader, () =>
43+
return dialectProvider.ReaderEach(reader, () =>
4444
{
4545
if (isObjectList)
4646
{
4747
var row = new List<object>();
48-
for (var i = 0; i < dataReader.FieldCount; i++)
48+
for (var i = 0; i < reader.FieldCount; i++)
4949
{
50-
row.Add(dataReader.GetValue(i));
50+
row.Add(reader.GetValue(i));
5151
}
5252
return (T)(object)row;
5353
}
5454
else if (isObjectDict)
5555
{
5656
var row = new Dictionary<string,object>();
57-
for (var i = 0; i < dataReader.FieldCount; i++)
57+
for (var i = 0; i < reader.FieldCount; i++)
5858
{
59-
row[dataReader.GetName(i).Trim()] = dataReader.GetValue(i);
59+
row[reader.GetName(i).Trim()] = reader.GetValue(i);
6060
}
6161
return (T)(object)row;
6262
}
6363
else
6464
{
6565
var row = CreateInstance<T>();
66-
row.PopulateWithSqlReader(dialectProvider, dataReader, fieldDefs, indexCache);
66+
row.PopulateWithSqlReader(dialectProvider, reader, indexCache, values);
6767
return row;
6868
}
6969
}, token).Then(t => {
70-
dataReader.Dispose();
70+
reader.Dispose();
7171
return t;
7272
});
7373
}
7474

75-
public static Task<object> ConvertToAsync(this IDataReader dataReader, IOrmLiteDialectProvider dialectProvider, Type type, CancellationToken token)
75+
public static Task<object> ConvertToAsync(this IDataReader reader, IOrmLiteDialectProvider dialectProvider, Type type, CancellationToken token)
7676
{
7777
var modelDef = type.GetModelDefinition();
78-
var fieldDefs = modelDef.AllFieldDefinitionsArray;
79-
80-
return dialectProvider.ReaderRead(dataReader, () =>
78+
var indexCache = reader.GetIndexFieldsCache(modelDef, dialectProvider);
79+
var values = new object[reader.FieldCount];
80+
return dialectProvider.ReaderRead(reader, () =>
8181
{
8282
var row = type.CreateInstance();
83-
var indexCache = dataReader.GetIndexFieldsCache(modelDef);
84-
row.PopulateWithSqlReader(dialectProvider, dataReader, fieldDefs, indexCache);
83+
row.PopulateWithSqlReader(dialectProvider, reader, indexCache, values);
8584
return row;
8685
}, token).Then(t =>
8786
{
88-
dataReader.Dispose();
87+
reader.Dispose();
8988
return t;
9089
});
9190
}
9291

93-
public static Task<IList> ConvertToListAsync(this IDataReader dataReader, IOrmLiteDialectProvider dialectProvider, Type type, CancellationToken token)
92+
public static Task<IList> ConvertToListAsync(this IDataReader reader, IOrmLiteDialectProvider dialectProvider, Type type, CancellationToken token)
9493
{
9594
var modelDef = type.GetModelDefinition();
96-
var fieldDefs = modelDef.AllFieldDefinitionsArray;
97-
98-
var indexCache = dataReader.GetIndexFieldsCache(modelDef);
99-
return dialectProvider.ReaderEach(dataReader, () =>
95+
var indexCache = reader.GetIndexFieldsCache(modelDef, dialectProvider);
96+
var values = new object[reader.FieldCount];
97+
return dialectProvider.ReaderEach(reader, () =>
10098
{
10199
var row = type.CreateInstance();
102-
row.PopulateWithSqlReader(dialectProvider, dataReader, fieldDefs, indexCache);
100+
row.PopulateWithSqlReader(dialectProvider, reader, indexCache, values);
103101
return row;
104102
}, token)
105103
.Then(x =>
106104
{
107-
dataReader.Dispose();
105+
reader.Dispose();
108106
var to = (IList)typeof(List<>).MakeGenericType(type).CreateInstance();
109107
x.Each(o => to.Add(o));
110108
return to;

src/ServiceStack.OrmLite/Async/ReadExpressionCommandExtensionsAsync.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -158,16 +158,15 @@ internal static Task<T> ExprConvertToAsync<T>(this IDataReader dataReader, IOrmL
158158
() => dataReader.ConvertTo<T>(dialectProvider), token);
159159
}
160160

161-
internal static Task<List<T>> ExprConvertToListAsync<T>(this IDataReader dataReader, IOrmLiteDialectProvider dialectProvider, CancellationToken token)
161+
internal static Task<List<T>> ExprConvertToListAsync<T>(this IDataReader reader, IOrmLiteDialectProvider dialectProvider, CancellationToken token)
162162
{
163-
var fieldDefs = ModelDefinition<T>.Definition.AllFieldDefinitionsArray;
163+
var indexCache = reader.GetIndexFieldsCache(ModelDefinition<T>.Definition, dialectProvider);
164+
var values = new object[reader.FieldCount];
164165

165-
var indexCache = dataReader.GetIndexFieldsCache(ModelDefinition<T>.Definition);
166-
167-
return dialectProvider.ReaderEach(dataReader, () =>
166+
return dialectProvider.ReaderEach(reader, () =>
168167
{
169168
var row = OrmLiteUtils.CreateInstance<T>();
170-
row.PopulateWithSqlReader(dialectProvider, dataReader, fieldDefs, indexCache);
169+
row.PopulateWithSqlReader(dialectProvider, reader, indexCache, values);
171170
return row;
172171
}, token);
173172
}

src/ServiceStack.OrmLite/IOrmLiteDialectProvider.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ public interface IOrmLiteDialectProvider
3636
/// </summary>
3737
IOrmLiteConverter GetConverterBestMatch(Type type);
3838

39+
IOrmLiteConverter GetConverterBestMatch(FieldDefinition fieldDef);
40+
3941
string ParamString { get; set; }
4042

4143
[Obsolete("Use GetStringConverter().UseUnicode")]
@@ -62,8 +64,6 @@ public interface IOrmLiteDialectProvider
6264

6365
object GetParamValue(object value, Type fieldType);
6466

65-
void SetDbValue(FieldDefinition fieldDef, IDataReader reader, int colIndex, object instance);
66-
6767
object ToDbValue(object value, Type type);
6868

6969
object FromDbValue(object value, Type type);

src/ServiceStack.OrmLite/ModelDefinition.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,11 @@ public FieldDefinition GetFieldDefinition<T>(Expression<Func<T, object>> field)
122122
return FieldDefinitions.First(f => f.Name == fn);
123123
}
124124

125+
public FieldDefinition GetFieldDefinition(string fieldName)
126+
{
127+
return FieldDefinitions.FirstOrDefault(f => f.Name == fieldName);
128+
}
129+
125130
string GetFieldName<T>(Expression<Func<T, object>> field)
126131
{
127132

src/ServiceStack.OrmLite/OrmLiteDialectProviderBase.cs

Lines changed: 10 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -295,47 +295,19 @@ public virtual ulong FromDbRowVersion(object value)
295295
return RowVersionConverter.FromDbRowVersion(value);
296296
}
297297

298-
/// <summary>
299-
/// Populates row fields during re-hydration of results.
300-
/// </summary>
301-
public virtual void SetDbValue(FieldDefinition fieldDef, IDataReader reader, int colIndex, object instance)
298+
public virtual IOrmLiteConverter GetConverterBestMatch(FieldDefinition fieldDef)
302299
{
303-
if (OrmLiteUtils.HandledDbNullValue(fieldDef, reader, colIndex, instance)) return;
304-
305300
var fieldType = Nullable.GetUnderlyingType(fieldDef.FieldType) ?? fieldDef.FieldType;
301+
if (fieldDef.IsRowVersion)
302+
return RowVersionConverter;
306303

307-
IOrmLiteConverter converter = null;
308-
object value = null;
309-
try
310-
{
311-
if (fieldDef.IsRowVersion)
312-
{
313-
converter = RowVersionConverter;
314-
value = converter.FromDbValue(fieldDef.FieldType, converter.GetValue(reader, colIndex));
315-
if (value != null)
316-
fieldDef.SetValueFn(instance, value);
317-
return;
318-
}
319-
320-
if (Converters.TryGetValue(fieldType, out converter))
321-
{
322-
value = converter.FromDbValue(fieldDef.FieldType, converter.GetValue(reader, colIndex));
323-
fieldDef.SetValueFn(instance, value);
324-
return;
325-
}
304+
IOrmLiteConverter converter;
305+
if (Converters.TryGetValue(fieldType, out converter))
306+
return converter;
326307

327-
converter = fieldType.IsRefType()
328-
? (IOrmLiteConverter)ReferenceTypeConverter
329-
: ValueTypeConverter;
330-
value = converter.FromDbValue(fieldDef.FieldType, converter.GetValue(reader, colIndex));
331-
fieldDef.SetValueFn(instance, value);
332-
}
333-
catch (Exception ex)
334-
{
335-
Log.Error("Error in {0}.FromDbValue() on field '{1}' converting from '{2}' to '{3}'"
336-
.Fmt(converter.GetType().Name, fieldDef.Name, value != null ? value.GetType().Name : "undefined", fieldDef.FieldType.Name), ex);
337-
throw;
338-
}
308+
return fieldType.IsRefType()
309+
? (IOrmLiteConverter)ReferenceTypeConverter
310+
: ValueTypeConverter;
339311
}
340312

341313
public virtual object ToDbValue(object value, Type type)
@@ -408,7 +380,7 @@ public object GetValue(IDataReader reader, int columnIndex, Type type)
408380
{
409381
IOrmLiteConverter converter;
410382
if (Converters.TryGetValue(type, out converter))
411-
return converter.GetValue(reader, columnIndex);
383+
return converter.GetValue(reader, columnIndex, null);
412384

413385
return reader.GetValue(columnIndex);
414386
}

src/ServiceStack.OrmLite/OrmLiteReadCommandExtensions.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -535,14 +535,14 @@ internal static IEnumerable<T> SelectLazy<T>(this IDbCommand dbCmd, string sql,
535535
yield break;
536536
}
537537

538-
var fieldDefs = ModelDefinition<T>.Definition.FieldDefinitionsArray;
539538
using (var reader = dbCmd.ExecuteReader())
540539
{
541-
var indexCache = reader.GetIndexFieldsCache(ModelDefinition<T>.Definition);
540+
var indexCache = reader.GetIndexFieldsCache(ModelDefinition<T>.Definition, dialectProvider);
541+
var values = new object[reader.FieldCount];
542542
while (reader.Read())
543543
{
544544
var row = OrmLiteUtils.CreateInstance<T>();
545-
row.PopulateWithSqlReader(dialectProvider, reader, fieldDefs, indexCache);
545+
row.PopulateWithSqlReader(dialectProvider, reader, indexCache, values);
546546
yield return row;
547547
}
548548
}
@@ -598,15 +598,15 @@ internal static IEnumerable<T> WhereLazy<T>(this IDbCommand dbCmd, object anonTy
598598
yield break;
599599
}
600600

601-
var fieldDefs = ModelDefinition<T>.Definition.FieldDefinitionsArray;
602601
var dialectProvider = dbCmd.GetDialectProvider();
603602
using (var reader = dbCmd.ExecuteReader())
604603
{
605-
var indexCache = reader.GetIndexFieldsCache(ModelDefinition<T>.Definition);
604+
var indexCache = reader.GetIndexFieldsCache(ModelDefinition<T>.Definition, dialectProvider);
605+
var values = new object[reader.FieldCount];
606606
while (reader.Read())
607607
{
608608
var row = OrmLiteUtils.CreateInstance<T>();
609-
row.PopulateWithSqlReader(dialectProvider, reader, fieldDefs, indexCache);
609+
row.PopulateWithSqlReader(dialectProvider, reader, indexCache, values);
610610
yield return row;
611611
}
612612
}
@@ -631,14 +631,14 @@ internal static IEnumerable<T> SelectLazyFmt<T>(this IDbCommand dbCmd, string fi
631631
yield break;
632632
}
633633

634-
var fieldDefs = ModelDefinition<T>.Definition.FieldDefinitionsArray;
635634
using (var reader = dbCmd.ExecReader(dbCmd.CommandText))
636635
{
637-
var indexCache = reader.GetIndexFieldsCache(ModelDefinition<T>.Definition);
636+
var indexCache = reader.GetIndexFieldsCache(ModelDefinition<T>.Definition, dialectProvider);
637+
var values = new object[reader.FieldCount];
638638
while (reader.Read())
639639
{
640640
var row = OrmLiteUtils.CreateInstance<T>();
641-
row.PopulateWithSqlReader(dialectProvider, reader, fieldDefs, indexCache);
641+
row.PopulateWithSqlReader(dialectProvider, reader, indexCache, values);
642642
yield return row;
643643
}
644644
}
@@ -683,8 +683,8 @@ internal static T ToScalar<T>(IOrmLiteDialectProvider dialectProvider, IDataRead
683683
var converter = dialectProvider.GetConverterBestMatch(underlyingType);
684684
if (converter != null)
685685
{
686-
object oValue = converter.GetValue(reader, columnIndex);
687-
if (oValue == null || oValue == DBNull.Value)
686+
object oValue = converter.GetValue(reader, columnIndex, null);
687+
if (oValue == null)
688688
return default(T);
689689

690690
var convertedValue = converter.FromDbValue(underlyingType, oValue);

0 commit comments

Comments
 (0)