static Expression ConvertExpressionToType(Expression current, Type toType, MappingSchema mappingSchema) { var toConvertExpression = mappingSchema.GetConvertExpression(current.Type, toType, false, current.Type != toType); if (toConvertExpression == null) { return(current); } current = InternalExtensions.ApplyLambdaToExpression(toConvertExpression, current); return(current); }
static Expression GetColumnReader( IDataContext dataContext, MappingSchema mappingSchema, IDataReader dataReader, Type type, IValueConverter?converter, int idx, Expression dataReaderExpr, bool forceNullCheck) { var toType = type.ToNullableUnderlying(); Expression ex; if (converter != null) { var expectedProvType = converter.FromProviderExpression.Parameters[0].Type; ex = dataContext.GetReaderExpression(dataReader, idx, dataReaderExpr, expectedProvType); } else { ex = dataContext.GetReaderExpression(dataReader, idx, dataReaderExpr, toType); } if (ex.NodeType == ExpressionType.Lambda) { var l = (LambdaExpression)ex; switch (l.Parameters.Count) { case 1: ex = l.GetBody(dataReaderExpr); break; case 2: ex = l.GetBody(dataReaderExpr, ExpressionInstances.Int32(idx)); break; } } if (converter != null) { // we have to prepare read expression to conversion // var expectedType = converter.FromProviderExpression.Parameters[0].Type; if (converter.HandlesNulls) { ex = Condition( Call(dataReaderExpr, Methods.ADONet.IsDBNull, ExpressionInstances.Int32Array(idx)), Constant(mappingSchema.GetDefaultValue(expectedType), expectedType), ex); } if (expectedType != ex.Type) { ex = ConvertExpressionToType(ex, expectedType, mappingSchema); } ex = InternalExtensions.ApplyLambdaToExpression(converter.FromProviderExpression, ex); if (toType != ex.Type && toType.IsAssignableFrom(ex.Type)) { ex = Convert(ex, toType); } } else if (toType.IsEnum) { var mapType = ConvertBuilder.GetDefaultMappingFromEnumType(mappingSchema, toType) !; if (mapType != ex.Type) { // Use only defined convert var econv = mappingSchema.GetConvertExpression(ex.Type, type, false, false) ?? mappingSchema.GetConvertExpression(ex.Type, mapType, false) !; ex = InternalExtensions.ApplyLambdaToExpression(econv, ex); } } if (ex.Type != type) { ex = ConvertExpressionToType(ex, type, mappingSchema) !; } // Try to search postprocessing converter TType -> TType // ex = ConvertExpressionToType(ex, ex.Type, mappingSchema) !; // Add check null expression. // If converter handles nulls, do not provide IsNull check // Note: some providers may return wrong IsDBNullAllowed, so we enforce null check in slow mode. E.g.: // Microsoft.Data.SQLite // Oracle (group by columns) // MySql.Data and some other providers enforce null check in IsDBNullAllowed implementation if (converter?.HandlesNulls != true && (forceNullCheck || (dataContext.IsDBNullAllowed(dataReader, idx) ?? true))) { ex = Condition( Call(dataReaderExpr, Methods.ADONet.IsDBNull, ExpressionInstances.Int32Array(idx)), Constant(mappingSchema.GetDefaultValue(type), type), ex); } return(ex); }