static LambdaExpression CreateMappingLambda(Type typeT, List <Mapping <Thing, Thing> > mapping) { var result = Expression.Parameter(typeof(SqlDataRecord), "rec"); var metaDataParam = Expression.Parameter(typeof(SqlMetaData[]), "metaData"); var item = Expression.Parameter(typeT, "item"); var constructorInfo = typeof(SqlDataRecord).GetConstructor(new[] { typeof(SqlMetaData[]) }); var lines = new List <Expression> { Expression.Assign(result, Expression.New(constructorInfo, metaDataParam)) }; var propertiesAndFields = Types.ReadablePropertiesAndFieldsDictionary(typeT); var setNullMethod = typeof(SqlDataRecord).GetMethod("SetDBNull", new[] { typeof(int) }); Contract.Assert(setNullMethod != null); foreach (var map in mapping) { var col = (Column)map.To; var setValueExp = SetValue(result, item, map.From, col); if (setValueExp == null) { continue; } if (Types.CanBeNull(map.From.Type)) { lines.Add(Expression.IfThenElse( Expression.Equal(Expression.PropertyOrField(item, map.From.Name), Expression.Constant(null)), Expression.Call(result, setNullMethod, Expression.Constant(col.Ordinal)), setValueExp )); } else { lines.Add(setValueExp); } } lines.Add(result); var block = Expression.Block(new[] { result }, lines); var func = typeof(Func <, ,>).MakeGenericType(typeof(SqlMetaData[]), typeT, typeof(SqlDataRecord)); var lambdaExpression = Expression.Lambda(func, block, metaDataParam, item); return(lambdaExpression); }
static LambdaExpression CreatePrimativeLambda(Type typeT, Column col) { var result = Expression.Parameter(typeof(SqlDataRecord), "rec"); var metaDataParam = Expression.Parameter(typeof(SqlMetaData[]), "metaData"); var item = Expression.Parameter(typeT, "item"); var constructorInfo = typeof(SqlDataRecord).GetConstructor(new[] { typeof(SqlMetaData[]) }); var lines = new List <Expression> { Expression.Assign(result, Expression.New(constructorInfo, metaDataParam)) }; var setNullMethod = typeof(SqlDataRecord).GetMethod("SetDBNull", new[] { typeof(int) }); Contract.Assert(setNullMethod != null); var setValueExp = SetValue(result, col.Type, col, item); if (setValueExp == null) { throw new InvalidOperationException($"Cannot map from {typeT} to {col.Type}"); } if (Types.CanBeNull(typeT)) { lines.Add(Expression.IfThenElse( Expression.Equal(item, Expression.Constant(null)), Expression.Call(result, setNullMethod, Expression.Constant(col.Ordinal)), setValueExp )); } else { lines.Add(setValueExp); } lines.Add(result); var block = Expression.Block(new[] { result }, lines); var func = typeof(Func <, ,>).MakeGenericType(typeof(SqlMetaData[]), typeT, typeof(SqlDataRecord)); var lambdaExpression = Expression.Lambda(func, block, metaDataParam, item); return(lambdaExpression); }
static Action <DbCommand, object> CreateAddParametersAction(Type type) { var obj = Expression.Parameter(typeof(object), "obj"); var parameters = Expression.Parameter(type, "parameters"); var cmd = Expression.Parameter(typeof(DbCommand), "cmd"); var dataParam = Expression.Parameter(typeof(DbParameter), "dataParam"); var lines = new List <Expression> { Expression.Assign(parameters, Expression.Convert(obj, type)) }; var createParameter = typeof(DbCommand).GetMethod("CreateParameter", Type.EmptyTypes); foreach (var prop in Types.ReadablePublicFieldsAndProperties(type)) { var fieldOrProperty = Types.PropertyOrFieldType(prop); if (!IsSupportedType(fieldOrProperty)) { continue; } lines.Add(Expression.Assign(dataParam, Expression.Call(cmd, createParameter))); lines.Add(Expression.Assign(Expression.Property(dataParam, "ParameterName"), Expression.Constant("@" + prop.Name))); if (Types.IsStructured(fieldOrProperty)) { if (fieldOrProperty != typeof(SqlTable)) { throw new NotSupportedException($"Parameter {dataParam.Name} implements {nameof(IEnumerable<SqlDataRecord>)} but type name is unknown. Please wrap parameter by calling {nameof(Extensions.WithTypeName)}"); } lines.Add(Expression.IfThen( Expression.Not(Expression.TypeIs(cmd, typeof(DbCommand))), Expression.Throw(Expression.New(typeof(NotSupportedException).GetConstructor(new[] { typeof(string) }), Expression.Constant("Structured parameters are supported only for SqlCommand"))) )); lines.Add(Expression.Assign(Expression.Property(Expression.Convert(dataParam, typeof(SqlParameter)), "SqlDbType"), Expression.Constant(SqlDbType.Structured))); lines.Add(Expression.Assign(Expression.Property(Expression.Convert(dataParam, typeof(SqlParameter)), "TypeName"), Expression.Property(Expression.Property(parameters, prop.Name), "TypeName"))); } else if (fieldOrProperty.IsEnum || Types.IsNullableEnum(fieldOrProperty)) { lines.Add(Expression.Assign(Expression.Property(dataParam, "DbType"), Expression.Constant(DbType.Int32))); } else { lines.Add(Expression.Assign(Expression.Property(dataParam, "DbType"), Expression.Constant(Types.TypeToDbType[fieldOrProperty]))); } if (fieldOrProperty == typeof(SqlTable)) { // check if records is null var tt = Expression.PropertyOrField(parameters, prop.Name); var records = Expression.Property(Expression.Convert(tt, typeof(SqlTable)), "Records"); lines.Add( Expression.Assign(Expression.Property(dataParam, "Value"), Expression.Convert(records, typeof(object)) //Expression.Condition( // Expression.Equal(records, Expression.Constant(null)), // Expression.Convert(Expression.Field(null, typeof(DBNull), "Value"), typeof(object)), // Expression.Convert(records, typeof(object)) //) ) ); } else if (Types.CanBeNull(fieldOrProperty)) { lines.Add( Expression.Assign( Expression.Property(dataParam, "Value"), Expression.Condition( Expression.Equal(Expression.Property(parameters, prop.Name), Expression.Constant(null)), Expression.Convert(Expression.Field(null, typeof(DBNull), "Value"), typeof(object)), PropertyValueCastToObject(parameters, prop) ) ) ); } else { lines.Add(Expression.Assign(Expression.Property(dataParam, "Value"), PropertyValueCastToObject(parameters, prop))); } lines.Add(Expression.Call(Expression.Property(cmd, "Parameters"), typeof(DbParameterCollection).GetMethod("Add", new[] { typeof(object) }), dataParam)); } var block = Expression.Block(new[] { dataParam, parameters }, lines); return(Expression.Lambda <Action <DbCommand, object> >(block, cmd, obj).Compile()); }