/// <summary> /// Gets an Expression that gets the value of a POCO field or property. /// </summary> private Expression GetExpressionToGetValueFromPoco(ParameterExpression poco, PocoColumn column) { // Start by assuming the database wants the same type that the property is and that we'll just be getting the value from the property: // poco.SomeFieldOrProp Expression getValueFromPoco = Expression.MakeMemberAccess(poco, column.MemberInfo); if (column.MemberInfoType == column.ColumnType) { return(getValueFromPoco); } // See if there is a converter available for between the two types Delegate converter = _typeConverter.GetToDbConverter(column.MemberInfoType, column.ColumnType); if (converter == null) { // No converter available, at least try a cast: // (TColumn) poco.SomeFieldOrProp return(Expression.Convert(getValueFromPoco, column.ColumnType)); } // Invoke the converter: // converter(poco.SomeFieldOrProp) return(Expression.Call(converter.Target == null ? null : Expression.Constant(converter.Target), converter.Method, getValueFromPoco)); }
/// <summary> /// Creates a Func that collects all the values from a POCO (of type T) into an object[], with the values being in the array in the /// same order as the POCO's PocoData.Columns collection. /// </summary> private Func <T, object[]> CreateValueCollector <T>(bool primaryKeyValuesOnly) { PocoData pocoData = _pocoDataFactory.GetPocoData <T>(); // Create list to hold the method body and our input parameter, the POCO of type T var methodBodyExpressions = new List <Expression>(); ParameterExpression poco = Expression.Parameter(pocoData.PocoType, "poco"); // Figure out which collection of columns to use IList <PocoColumn> columns = primaryKeyValuesOnly == false ? pocoData.Columns : pocoData.GetPrimaryKeyColumns(); // Create a variable to hold our return value, and initialize as an object[] of correct size var values = Expression.Variable(typeof(object[]), "values"); methodBodyExpressions.Add( // object[] values = new object[... number of columns on POCO ...]; Expression.Assign(values, Expression.NewArrayBounds(ObjectType, Expression.Constant(columns.Count, IntType)))); for (var idx = 0; idx < columns.Count; idx++) { PocoColumn column = columns[idx]; // Figure out how to get the Expression getValueFromPoco = GetExpressionToGetValueFromPoco(poco, column); // values[columnIndex] = (object) ... getValueFromPoco ... methodBodyExpressions.Add( Expression.Assign(Expression.ArrayAccess(values, Expression.Constant(idx, IntType)), Expression.Convert(getValueFromPoco, ObjectType)) ); } // Return our values array methodBodyExpressions.Add(values); // Construct the method body, then create a compiled Func for the method var methodBody = Expression.Block(new[] { values }, methodBodyExpressions); return(Expression.Lambda <Func <T, object[]> >(methodBody, poco).Compile()); }