src/Cassandra/Mapping/MapperFactory.cs
/// <summary>
/// Creates a mapper Func for a POCO.
/// </summary>
Creates a mapper Func for a POCO.
Creates a mapper Func for a POCO .
private Func<Row, T> CreateMapperForPoco<T>(RowSet rows, PocoData pocoData)
        {
            ICollection<Expression> methodBodyExpressions = new LinkedList<Expression>();
            ParameterExpression row = Expression.Parameter(CassandraRowType, "row");
            var poco = Expression.Variable(pocoData.PocoType, "poco");
            if (pocoData.PocoType.GetTypeInfo().GetConstructor(Type.EmptyTypes) != null)
            {
                methodBodyExpressions.Add(Expression.Assign(poco, Expression.New(pocoData.PocoType)));
            }
            else
            {
                var constructor = pocoData.PocoType.GetTypeInfo().GetConstructors().FirstOrDefault(c => c.GetParameters().Length == rows.Columns.Length);
                if (constructor == null)
                {
                    throw new ArgumentException(
                        String.Format("RowSet columns length is {0} but type {1} does not contain a constructor with the same amount of parameters", 
                        rows.Columns.Length,
                        pocoData.PocoType));
                }
                var parameterInfos = constructor.GetParameters();
                var parameterExpressions = new List<Expression>();
                for (var i = 0; i < rows.Columns.Length; i++)
                {
                    var c = rows.Columns[i];
                    var param = parameterInfos[i];
                    var getValueT = GetExpressionToGetColumnValueFromRow(row, c, param.ParameterType);
                    parameterExpressions.Add(getValueT);
                }
                methodBodyExpressions.Add(Expression.Assign(poco, Expression.New(constructor, parameterExpressions)));
            }
            var methodBodyVariables = new List<ParameterExpression> { poco };
            foreach (var dbColumn in rows.Columns)
            {
                PocoColumn pocoColumn;
                if (pocoData.Columns.TryGetItem(dbColumn.Name, out pocoColumn) == false)
                    continue;
                Expression getColumnValue = GetExpressionToGetColumnValueFromRow(row, dbColumn, pocoColumn.MemberInfoType);
                BinaryExpression getValueAndAssign = Expression.Assign(Expression.MakeMemberAccess(poco, pocoColumn.MemberInfo), getColumnValue);
                Expression ifRowValueIsNull = Expression.Empty();
                Expression createEmptyCollection;
                if (TryGetCreateEmptyCollectionExpression(dbColumn, pocoColumn.MemberInfoType, out createEmptyCollection))
                {
                    ifRowValueIsNull = Expression.Assign(Expression.MakeMemberAccess(poco, pocoColumn.MemberInfo), createEmptyCollection);
                }
                var columnIndex = Expression.Constant(dbColumn.Index, IntType);
                methodBodyExpressions.Add(Expression.IfThenElse(Expression.IsFalse(Expression.Call(row, IsNullMethod, columnIndex)),
                    getValueAndAssign,
                    ifRowValueIsNull));
            }
            methodBodyExpressions.Add(poco);
            BlockExpression methodBody = Expression.Block(methodBodyVariables, methodBodyExpressions);
            return Expression.Lambda<Func<Row, T>>(methodBody, row).Compile();
        }
private Func < Row , T > CreateMapperForPoco < T > ( RowSet rows , PocoData pocoData ) { ICollection < Expression > methodBodyExpressions = new LinkedList < Expression > ( ) ; ParameterExpression row = Expression . Parameter ( CassandraRowType , " " ) ; var poco = Expression . Variable ( pocoData . PocoType , " " ) ; if ( pocoData . PocoType . GetTypeInfo ( ) . GetConstructor ( Type . EmptyTypes ) != null ) { methodBodyExpressions . Add ( Expression . Assign ( poco , Expression . New ( pocoData . PocoType ) ) ) ; } else { var constructor = pocoData . PocoType . GetTypeInfo ( ) . GetConstructors ( ) . FirstOrDefault ( c => c . GetParameters ( ) . Length == rows . Columns . Length ) ; if ( constructor == null ) { throw new ArgumentException ( String . Format ( " " , rows . Columns . Length , pocoData . PocoType ) ) ; } var parameterInfos = constructor . GetParameters ( ) ; var parameterExpressions = new List < Expression > ( ) ; for ( var i = 0 ; i < rows . Columns . Length ; i ++ ) { var c = rows . Columns [ i ] ; var param = parameterInfos [ i ] ; var getValueT = GetExpressionToGetColumnValueFromRow ( row , c , param . ParameterType ) ; parameterExpressions . Add ( getValueT ) ; } methodBodyExpressions . Add ( Expression . Assign ( poco , Expression . New ( constructor , parameterExpressions ) ) ) ; } var methodBodyVariables = new List < ParameterExpression > { poco } ; foreach ( var dbColumn in rows . Columns ) { PocoColumn pocoColumn ; if ( pocoData . Columns . TryGetItem ( dbColumn . Name , out pocoColumn ) == false ) continue ; Expression getColumnValue = GetExpressionToGetColumnValueFromRow ( row , dbColumn , pocoColumn . MemberInfoType ) ; BinaryExpression getValueAndAssign = Expression . Assign ( Expression . MakeMemberAccess ( poco , pocoColumn . MemberInfo ) , getColumnValue ) ; Expression ifRowValueIsNull = Expression . Empty ( ) ; Expression createEmptyCollection ; if ( TryGetCreateEmptyCollectionExpression ( dbColumn , pocoColumn . MemberInfoType , out createEmptyCollection ) ) { ifRowValueIsNull = Expression . Assign ( Expression . MakeMemberAccess ( poco , pocoColumn . MemberInfo ) , createEmptyCollection ) ; } var columnIndex = Expression . Constant ( dbColumn . Index , IntType ) ; methodBodyExpressions . Add ( Expression . IfThenElse ( Expression . IsFalse ( Expression . Call ( row , IsNullMethod , columnIndex ) ) , getValueAndAssign , ifRowValueIsNull ) ) ; } methodBodyExpressions . Add ( poco ) ; BlockExpression methodBody = Expression . Block ( methodBodyVariables , methodBodyExpressions ) ; return Expression . Lambda < Func < Row , T > > ( methodBody , row ) . Compile ( ) ; }
Creates a mapper Func for a POCO.
Creates a mapper Func for a POCO .
// We're going to store the method body expressions in a list since we need to use some looping to generate it // The input parameter for our Func<Row, T>, a C* Row // T poco = new T(); //It has default constructor // Keep track of any variables we need in the method body, starting with the poco variable // Try to find a corresponding column on the POCO and if not found, don't map that column from the RowSet // Figure out if we're going to need to do any casting/conversion when we call Row.GetValue<T>(columnIndex) // poco.SomeFieldOrProp = ... getColumnValue call ... // Start with an expression that does nothing if the row is null // Cassandra will return null for empty collections, so make an effort to populate collection properties on the POCO with // empty collections instead of null in those cases // 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
pocoData
PocoData