Esempio n. 1
0
        private Func <IDataReader, T> CompileMapperFunction()
        {
            var exps = new List <Expression>();

            var dataReaderExprParam = Expression.Parameter(typeof(IDataRecord), "datareader");

            var targetExp = Expression.Variable(typeof(T));

            //var target = new T();
            exps.Add(Expression.Assign(targetExp, Expression.New(targetExp.Type)));

            //does int based lookup
            var indexerInfo = typeof(IDataRecord).GetProperty("Item", new[] { typeof(int) });

            var columnNames = Enumerable.Range(0, _dataReader.FieldCount)
                              .Select(i => new { index = i, name = _dataReader.GetName(i) });
            var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

            foreach (var column in columnNames)
            {
                var property = AttributeExtension.GetUnderlyingPropertyByName(properties, column.name);
                if (property == null)
                {
                    continue;
                }

                var readerIndex = Expression.Constant(column.index);
                // equivalent to datareader[(int)readerIndex] where datareader is incoming parameter.
                var valueExpr = Expression.MakeIndex(dataReaderExprParam, indexerInfo, new[] { readerIndex });

                var        actualType = _dataReader.GetFieldType(column.index);
                Expression safeCastExpression;
                //if property type in model doesn't match the underlying type in SQL, we first convert into actual SQL type.
                if (actualType != property.PropertyType)
                {
                    safeCastExpression = Expression.Convert(valueExpr, actualType);
                }
                //otherwise we do nothing.
                else
                {
                    safeCastExpression = valueExpr;
                }
                var isReaderDbNull     = Expression.Call(dataReaderExprParam, "IsDBNull", null, readerIndex);
                var propertyExpression = Expression.Property(targetExp, property);

                /*
                 * if(datareader.IsDBNull((int)readerIndex){
                 *  target.property = default;
                 * }else{
                 *  target.property = (castType)value;
                 * }
                 */
                var assignmentBlock = Expression.Condition(
                    Expression.IsTrue(isReaderDbNull),
                    Expression.Assign(propertyExpression, Expression.Default(property.PropertyType)),
                    Expression.Assign(propertyExpression, Expression.Convert(safeCastExpression, property.PropertyType)
                                      )
                    );
                exps.Add(assignmentBlock);
            }
            //return target;
            exps.Add(targetExp);
            var func = Expression.Lambda <Func <IDataReader, T> >(
                Expression.Block(new[] { targetExp }, exps), dataReaderExprParam);

            return(func.Compile());
        }