Last active
December 14, 2015 01:28
-
-
Save darrenkopp/5005932 to your computer and use it in GitHub Desktop.
Some handy utilities for dealing with ado.net
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static class DataReaderExtensions | |
{ | |
public static IEnumerable<T> Stream<T>(this IDbCommand command, Func<IDataRecord, T> converter) | |
{ | |
using (var reader = command.ExecuteReader(CommandBehavior.SingleResult)) | |
{ | |
while (reader.Read()) | |
yield return converter(reader); | |
} | |
} | |
public static Nullable<T> ValueOrNull<T>(this IDataRecord record, string field) where T : struct | |
{ | |
var value = record[field]; | |
if (value == DBNull.Value) | |
return new Nullable<T>(); | |
return (T)value; | |
} | |
public static T ValueOrDefault<T>(this IDataRecord record, string field) | |
{ | |
var value = record[field]; | |
if (value == DBNull.Value) | |
return default(T); | |
return (T)value; | |
} | |
public static long? Long(this IDataRecord record, string column) | |
{ | |
var value = record[column]; | |
if (value == DBNull.Value) | |
return null; | |
return (long)value; | |
} | |
public static string String(this IDataRecord record, string column) | |
{ | |
var value = record[column]; | |
if (value == DBNull.Value) | |
return null; | |
return (string)value; | |
} | |
public static Guid? Guid(this IDataRecord record, string column) | |
{ | |
var value = record[column]; | |
if (value == DBNull.Value) | |
return null; | |
return (Guid)value; | |
} | |
public static DateTime? Date(this IDataRecord record, string column) | |
{ | |
var value = record[column]; | |
if (value == DBNull.Value) | |
return null; | |
return (DateTime)value; | |
} | |
public static int? Int(this IDataRecord record, string column) | |
{ | |
var value = record[column]; | |
if (value == DBNull.Value) | |
return null; | |
return (int)value; | |
} | |
public static bool? Boolean(this IDataRecord record, string column) | |
{ | |
var value = record[column]; | |
if (value == DBNull.Value) | |
return null; | |
if (value is bool) | |
return (bool)value; | |
if (value is int) | |
return ((int)value) == 1; | |
return Convert.ToBoolean(value); | |
} | |
public static long? RowVersion(this IDataRecord record, string column) | |
{ | |
object value = record[column]; | |
if (value == DBNull.Value) | |
return null; | |
// can't use BitConverter as value coming out is big-endian | |
byte[] bytes = (byte[])value; | |
long ret = 0; | |
for (int i = 0; i < 8; i++) | |
{ | |
ret = unchecked((ret << 8) | bytes[i]); | |
} | |
return ret; | |
} | |
public static decimal? Decimal(this IDataRecord record, string column) | |
{ | |
var value = record[column]; | |
if (value == DBNull.Value) | |
return null; | |
return (decimal)value; | |
} | |
public static byte[] Binary(this IDataRecord record, string column) | |
{ | |
int idx = record.GetOrdinal(column); | |
if (record.IsDBNull(idx)) | |
return null; | |
// copy data into memory | |
using (var memory = new MemoryStream()) | |
{ | |
int bufferSize = 4096; | |
byte[] buffer = new byte[bufferSize]; | |
int offset = 0; | |
while (true) | |
{ | |
// read in the data and increment our offset | |
long length = record.GetBytes(idx, offset, buffer, 0, bufferSize); | |
offset += bufferSize; | |
// write the resulting bytes to the memory stream | |
memory.Write(buffer, 0, (int)length); | |
// if we didn't read full buffer, then we are likely done | |
if (length < bufferSize) | |
break; | |
} | |
return memory.ToArray(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class DataTranslator | |
{ | |
public static Func<IDataRecord, T> CreateTranslator<T>(IDataRecord record) | |
{ | |
// get all properties that are translated | |
var propertyDictionary = targetType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty) | |
.Where(p => !Attribute.IsDefined(p, typeof(NotTranslatedAttribute))) | |
.ToDictionary(p => p.Name.ToLower()); | |
var recordMappings = new Dictionary<int, PropertyInfo>(); | |
for (int i = 0; i < record.FieldCount; i++) | |
{ | |
string fieldName = record.GetName(i).ToLower(); | |
if (propertyDictionary.ContainsKey(fieldName)) | |
recordMappings.Add(i, propertyDictionary[fieldName]); | |
} | |
// Create Methods to GetValue and check for null from record | |
Type dataRecordType = typeof(IDataRecord); | |
MethodInfo recordGetValue = dataRecordType.GetMethod("GetValue"); | |
MethodInfo recordIsDBNull = dataRecordType.GetMethod("IsDBNull"); | |
// create parameter for record | |
ParameterExpression rec = Expression.Parameter(dataRecordType, "record"); | |
Expression<Func<IDataRecord, T>> translator = Expression.Lambda<Func<IDataRecord, T>>( | |
Expression.MemberInit(Expression<T>.New(targetType), | |
recordMappings.Select(mapping => | |
{ | |
// property can handle a null value | |
if ((mapping.Value.PropertyType.IsValueType == false) || (mapping.Value.PropertyType.IsGenericType && mapping.Value.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))) | |
{ | |
var conversion = Expression.Condition( | |
Expression<bool>.Call(rec, recordIsDBNull, Expression<int>.Constant(mapping.Key)), | |
Expression.TypeAs(Expression.Constant(null), mapping.Value.PropertyType), | |
Expression.TypeAs(Expression.Call(rec, recordGetValue, Expression<int>.Constant(mapping.Key)), mapping.Value.PropertyType) | |
); | |
return Expression.Bind(mapping.Value, conversion) as MemberBinding; | |
} | |
// handle enumerations | |
if (mapping.Value.PropertyType.IsEnum) | |
{ | |
// converts the type returned by the record to that of the underlying type of the enumeration | |
Expression<Func<object, Type, object>> converter = (item, toType) => Convert.ChangeType(item, toType); | |
var underlyingType = Enum.GetUnderlyingType(mapping.Value.PropertyType); | |
var fieldType = record.GetFieldType(mapping.Key); | |
// by default, the value for conversion is what we get from the record.GetValue method call | |
Expression valueForConversionExpression = Expression.Call(rec, recordGetValue, Expression<int>.Constant(mapping.Key)); | |
if (underlyingType != fieldType) | |
{ | |
// the field types don't match, so the value we'll pass to the conversion method will be the result | |
// of the Convert.ChangeType method | |
valueForConversionExpression = Expression.Invoke( | |
converter, | |
new Expression[] { | |
valueForConversionExpression, | |
Expression<Type>.Constant(underlyingType) | |
} | |
); | |
} | |
// return the binding expression | |
return Expression.Bind( | |
mapping.Value, | |
Expression.Convert( | |
valueForConversionExpression, | |
mapping.Value.PropertyType | |
) | |
) as MemberBinding; | |
} | |
// plain ol' struct, just return the conversion | |
return Expression.Bind(mapping.Value, Expression.Convert(Expression.Call(rec, recordGetValue, Expression<int>.Constant(mapping.Key)), mapping.Value.PropertyType)) as MemberBinding; | |
}) | |
), rec | |
); | |
return translator.Compile(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment