/// <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), GetMethod(converter), 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> /// <param name="primaryKeyValuesOnly">Determines if only the primary key values should be extracted</param> /// <param name="primaryKeyValuesLast">Determines if only the values should contain first the non primary keys and then the primary keys</param> private Func <T, object[]> CreateValueCollector <T>(bool primaryKeyValuesOnly, bool primaryKeyValuesLast) { 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 = pocoData.Columns; if (primaryKeyValuesOnly) { //pk columns only columns = pocoData.GetPrimaryKeyColumns(); } if (primaryKeyValuesLast) { //normal columns + pk columns var pkColumns = pocoData.GetPrimaryKeyColumns(); columns = pocoData.Columns .Except(pkColumns) .Concat(pkColumns) .ToList(); } // 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()); }
public object AdaptValue(PocoData pocoData, PocoColumn column, object value) { if (column.MemberInfoType == column.ColumnType) { return(value); } // See if there is a converter available for between the two types var converter = _typeConverter.GetToDbConverter(column.MemberInfoType, column.ColumnType); if (converter == null) { // No converter available, at least try a cast: // (TColumn) poco.SomeFieldOrProp return(Convert.ChangeType(value, column.ColumnType)); } return(converter.DynamicInvoke(value)); }