src/Cassandra/Mapping/MapperFactory.cs
/// <summary>
/// Creates a mapper Func for a projection.
/// </summary>
Creates a mapper Func for a projection.
Creates a mapper Func for a projection .
private Func<Row, T> CreateMapperForProjection<T>(RowSet rows, NewTypeProjection projection)
        {
            ICollection<Expression> methodBodyExpressions = new LinkedList<Expression>();
            ParameterExpression row = Expression.Parameter(CassandraRowType, "row");
            ParameterExpression poco = Expression.Variable(typeof(T), "poco");
            var constructorParameters = projection.ConstructorInfo.GetParameters();
            var columnIndex = 0;
            if (constructorParameters.Length == 0)
            {
                methodBodyExpressions.Add(Expression.Assign(poco, Expression.New(projection.ConstructorInfo)));
            }
            else
            {
                var parameterExpressions = new List<Expression>();
                if (constructorParameters.Length > rows.Columns.Length)
                {
                    throw new IndexOutOfRangeException(string.Format("Expected at least {0} column(s), obtained {1}",
                        constructorParameters.Length, rows.Columns.Length));
                }
                for (columnIndex = 0; columnIndex < constructorParameters.Length; columnIndex++)
                {
                    var c = rows.Columns[columnIndex];
                    var param = constructorParameters[columnIndex];
                    var getValueT = GetExpressionToGetColumnValueFromRow(row, c, param.ParameterType);
                    parameterExpressions.Add(getValueT);
                }
                methodBodyExpressions.Add(Expression.Assign(poco, 
                    Expression.New(projection.ConstructorInfo, parameterExpressions)));
            }
            var membersEnumerator = projection.Members.GetEnumerator();
            while (membersEnumerator.MoveNext() && columnIndex < rows.Columns.Length)
            {
                var member = membersEnumerator.Current;
                var c = rows.Columns[columnIndex];
                var memberType = GetUnderlyingType(member);
                var getColumnValue = GetExpressionToGetColumnValueFromRow(row, c, memberType);
                var getValueAndAssign = Expression.Assign(
                    Expression.MakeMemberAccess(poco, member), getColumnValue);
                Expression ifRowValueIsNull = Expression.Empty();
                Expression createEmptyCollection;
                if (TryGetCreateEmptyCollectionExpression(c, memberType, out createEmptyCollection))
                {
                    ifRowValueIsNull = Expression.Assign(Expression.MakeMemberAccess(poco, member), createEmptyCollection);
                }
                var columnIndexExpression = Expression.Constant(columnIndex, IntType);
                methodBodyExpressions.Add(Expression.IfThenElse(
                    Expression.IsFalse(Expression.Call(row, IsNullMethod, columnIndexExpression)), 
                    getValueAndAssign, 
                    ifRowValueIsNull));
                columnIndex++;
            }
            methodBodyExpressions.Add(poco);
            var methodBody = Expression.Block(new [] { poco }, methodBodyExpressions);
            return Expression.Lambda<Func<Row, T>>(methodBody, row).Compile();
        }
private Func < Row , T > CreateMapperForProjection < T > ( RowSet rows , NewTypeProjection projection ) { ICollection < Expression > methodBodyExpressions = new LinkedList < Expression > ( ) ; ParameterExpression row = Expression . Parameter ( CassandraRowType , " " ) ; ParameterExpression poco = Expression . Variable ( typeof ( T ) , " " ) ; var constructorParameters = projection . ConstructorInfo . GetParameters ( ) ; var columnIndex = 0 ; if ( constructorParameters . Length == 0 ) { methodBodyExpressions . Add ( Expression . Assign ( poco , Expression . New ( projection . ConstructorInfo ) ) ) ; } else { var parameterExpressions = new List < Expression > ( ) ; if ( constructorParameters . Length > rows . Columns . Length ) { throw new IndexOutOfRangeException ( string . Format ( " " , constructorParameters . Length , rows . Columns . Length ) ) ; } for ( columnIndex = 0 ; columnIndex < constructorParameters . Length ; columnIndex ++ ) { var c = rows . Columns [ columnIndex ] ; var param = constructorParameters [ columnIndex ] ; var getValueT = GetExpressionToGetColumnValueFromRow ( row , c , param . ParameterType ) ; parameterExpressions . Add ( getValueT ) ; } methodBodyExpressions . Add ( Expression . Assign ( poco , Expression . New ( projection . ConstructorInfo , parameterExpressions ) ) ) ; } var membersEnumerator = projection . Members . GetEnumerator ( ) ; while ( membersEnumerator . MoveNext ( ) && columnIndex < rows . Columns . Length ) { var member = membersEnumerator . Current ; var c = rows . Columns [ columnIndex ] ; var memberType = GetUnderlyingType ( member ) ; var getColumnValue = GetExpressionToGetColumnValueFromRow ( row , c , memberType ) ; var getValueAndAssign = Expression . Assign ( Expression . MakeMemberAccess ( poco , member ) , getColumnValue ) ; Expression ifRowValueIsNull = Expression . Empty ( ) ; Expression createEmptyCollection ; if ( TryGetCreateEmptyCollectionExpression ( c , memberType , out createEmptyCollection ) ) { ifRowValueIsNull = Expression . Assign ( Expression . MakeMemberAccess ( poco , member ) , createEmptyCollection ) ; } var columnIndexExpression = Expression . Constant ( columnIndex , IntType ) ; methodBodyExpressions . Add ( Expression . IfThenElse ( Expression . IsFalse ( Expression . Call ( row , IsNullMethod , columnIndexExpression ) ) , getValueAndAssign , ifRowValueIsNull ) ) ; columnIndex ++ ; } methodBodyExpressions . Add ( poco ) ; var methodBody = Expression . Block ( new [ ] { poco } , methodBodyExpressions ) ; return Expression . Lambda < Func < Row , T > > ( methodBody , row ) . Compile ( ) ; }
Creates a mapper Func for a projection.
Creates a mapper Func for a projection .
// The input parameter for our Func<Row, T>, a C* Row // poco variable // Use default constructor // T poco = new T() // T poco = new T(param1, param2, ...) // Fill the rest of members with the rest of the column values // ReSharper disable once GenericEnumeratorNotDisposed // poco.SomeFieldOrProp = ... getColumnValue call ... // Start with an expression that does nothing if the row is null // For collections, make an effort to return an empty collection instead of null // poco.SomeFieldOrProp = ... createEmptyCollection ... //Expression equivalent to // if (row.IsNull(columnIndex) == false) => getValueAndAssign ... // else => ifRowIsNull ... // The last expression in the method body is the return value, so put our new POCO at the end // Create a block expression for the method body expressions // Return compiled expression
rows
RowSet
projection
NewTypeProjection