/// <summary> /// 一括Insert用SQLを生成します。 /// </summary> /// <param name="builder">DBMSに応じたQueryBuilderオブジェクト</param> /// <param name="records">挿入するレコード(複数件)</param> /// <param name="targetColumns">値設定対象カラムを限定する場合は、対象カラムについての匿名型を返すラムダ式。例:「<c>t => new { t.Col1, t.Col2 }</c>」</param> /// <param name="escapeMethod">値をSQLリテラル値へと変換するメソッド。DBMSに応じたエスケープ処理を行うよう実装すること</param> /// <param name="sqlMaxLength">一括InsertのSQLの最大文字列長。省略可</param> /// <typeparam name="T">テーブルにマッピングされた型</typeparam> /// <returns>「insert into [テーブル]([各カラム]) values ([各設定値]),([各設定値])...」のSQLについて最大文字列長を超過しないよう分割して返す</returns> public static IEnumerable <string> BuildBulkInsert <T>(QueryBuilder builder, IEnumerable <T> records, LambdaExpression targetColumns, Func <object, string> escapeMethod, int sqlMaxLength = 100000000) { var tableInfo = builder.GetTableInfo <T>(); var columns = (targetColumns == null ? tableInfo.Columns.Where(c => c.Insert) : tableInfo.GetColumns(ExpressionHelper.GetMemberNames(targetColumns.Body))).ToArray(); var names = new StringBuilder(); foreach (var column in columns) { if (names.Length > 0) { names.Append(", "); } names.Append(column.Name); } var data = new StringBuilder(); foreach (var record in records) { var values = new StringBuilder(); foreach (var column in columns) { values.Append(values.Length == 0 ? "(" : ", "); values.Append(targetColumns != null || string.IsNullOrWhiteSpace(column.InsertSQL) ? escapeMethod(MemberAccessor.GetValue(record, column.PropertyInfo)) : column.InsertSQL); } values.Append(")"); if (data.Length + values.Length >= sqlMaxLength) { yield return(data.ToString()); data.Clear(); } data.AppendLine(data.Length == 0 ? "insert into " + tableInfo.Name + "(" + names.ToString() + ") values" : ","); data.Append(values.ToString()); } if (data.Length > 0) { yield return(data.ToString()); } }
/// <summary> /// 式木が表している具体的な値を返します。 /// </summary> /// <param name="exp">値を指定している式木</param> /// <returns>値</returns> public static object EvaluateValue(this Expression exp) { // Boxingを展開 var expression = exp.CastTo <Expression>(); if (expression is ConstantExpression) { // 定数:値を返す return((expression as ConstantExpression).Value); } if (expression is NewExpression) { // インスタンス生成:生成されたインスタンスを返す var expr = (expression as NewExpression); var parameters = expr.Arguments.Select(EvaluateValue).ToArray(); return(expr.Constructor.Invoke(parameters)); } if (expression is NewArrayExpression) { // 配列生成:生成された配列を返す var expr = (expression as NewArrayExpression); return(expr.Expressions.Select(EvaluateValue).ToArray()); } if (expression is MethodCallExpression) { // メソッド呼び出し:呼び出し結果を返す var expr = (expression as MethodCallExpression); var parameters = expr.Arguments.Select(EvaluateValue).ToArray(); var obj = (expr.Object == null) ? null : EvaluateValue(expr.Object); return(expr.Method.Invoke(obj, parameters)); } if (expression is InvocationExpression) { // ラムダ等の呼び出し:呼び出し結果を返す var invocation = (expression as InvocationExpression); var parameters = invocation.Arguments.Select(x => Expression.Parameter(x.Type)).ToArray(); var arguments = invocation.Arguments.Select(EvaluateValue).ToArray(); var lambda = Expression.Lambda(invocation, parameters); return(lambda.Compile().DynamicInvoke(arguments)); } if (expression is BinaryExpression && expression.NodeType == ExpressionType.ArrayIndex) { // 配列等のインデクサ:そのインデックスの値を返す var expr = (expression as BinaryExpression); var array = (Array)EvaluateValue(expr.Left); var index = expr.Right.Type == typeof(int) ? (int)EvaluateValue(expr.Right) : (long)EvaluateValue(expr.Right); return(array.GetValue(index)); } // メンバ(フィールドまたはプロパティ):プロパティ/フィールド値を取り出す // ※インスタンスメンバならインスタンス値を再帰把握 var member = (expression as MemberExpression); if (member != null) { if (member.Member.MemberType == MemberTypes.Property) { var info = (PropertyInfo)member.Member; return((member.Expression != null) ? MemberAccessor.GetValue(EvaluateValue(member.Expression), info) : MemberAccessor.GetStaticValue(info)); } if (member.Member.MemberType == MemberTypes.Field) { var info = (FieldInfo)member.Member; return((member.Expression != null) ? MemberAccessor.GetValue(EvaluateValue(member.Expression), info) : MemberAccessor.GetStaticValue(info)); } } // ここまでの処理で値を特定できなかった:実行して値を取り出す return(Expression.Lambda(expression).Compile().DynamicInvoke()); }
/// <summary> /// 式木が表している具体的な値を返します。 /// </summary> /// <param name="expression">値を指定している式木</param> /// <returns>値</returns> public static object EvaluateValue(this Expression expression) { if (expression is ConstantExpression) { // 定数:値を返す return((expression as ConstantExpression).Value); } if (expression is NewExpression) { // インスタンス生成:生成されたインスタンスを返す var expr = (expression as NewExpression); var parameters = expr.Arguments.Select(EvaluateValue).ToArray(); return(expr.Constructor.Invoke(parameters)); } if (expression is NewArrayExpression) { // 配列生成:生成された配列を返す var expr = (expression as NewArrayExpression); return(expr.Expressions.Select(EvaluateValue).ToArray()); } if (expression is MethodCallExpression) { // メソッド呼び出し:呼び出し結果を返す var expr = (expression as MethodCallExpression); var parameters = expr.Arguments.Select(EvaluateValue).ToArray(); var obj = (expr.Object == null) ? null : EvaluateValue(expr.Object); return(expr.Method.Invoke(obj, parameters)); } if (expression is InvocationExpression) { // ラムダ等の呼び出し:呼び出し結果を返す var invocation = (expression as InvocationExpression); var parameters = invocation.Arguments.Select(x => Expression.Parameter(x.Type)).ToArray(); var arguments = invocation.Arguments.Select(EvaluateValue).ToArray(); var lambda = Expression.Lambda(invocation, parameters); return(lambda.Compile().DynamicInvoke(arguments)); } if (expression is BinaryExpression && expression.NodeType == ExpressionType.ArrayIndex) { // 配列等のインデクサ:そのインデックスの値を返す var expr = (expression as BinaryExpression); var array = (Array)EvaluateValue(expr.Left); var index = expr.Right.Type == typeof(int) ? (int)EvaluateValue(expr.Right) : (long)EvaluateValue(expr.Right); return(array.GetValue(index)); } // フィールド/プロパティ:1つづつたどっていく var memberInfoList = new List <MemberInfo>(); var temp = CastTo <Expression>(expression); while (!(temp is ConstantExpression)) { var member = CastTo <MemberExpression>(temp); if (member == null) { // フィールドでもプロパティでもない if (expression != temp) { // 再帰 return(EvaluateValue(temp)); } else { // 再帰できない:ラムダ実行により値取得 var lambda = Expression.Lambda(expression); return(lambda.Compile().DynamicInvoke()); } } if (member.Expression == null) { // static if (member.Member.MemberType == MemberTypes.Property) { var info = (PropertyInfo)member.Member; return(MemberAccessor.GetStaticValue(info)); } if (member.Member.MemberType == MemberTypes.Field) { var info = (FieldInfo)member.Member; return(MemberAccessor.GetStaticValue(info)); } throw new EvaluateException("can't evaluate:" + member.Member.ToString()); } // instance memberInfoList.Add(member.Member); temp = CastTo <Expression>(member.Expression); } var value = ((ConstantExpression)temp).Value; for (var i = memberInfoList.Count - 1; i >= 0; i--) { var mi = memberInfoList[i]; if (mi is PropertyInfo) { value = MemberAccessor.GetValue(value, (mi as PropertyInfo)); } else if (mi is FieldInfo) { value = MemberAccessor.GetValue(value, (mi as FieldInfo)); } } return(value); }