FreeSql - 扩展InsertInto方法,自动补全表达式树中相同属性的初始化操作
封装了一个语法糖
/// <summary>
/// InsertInto基础上,自动补全表达式树中相同属性的初始化操作
/// <para>
/// 补全效果:x => new Person {Name = x.Name, Age = x.Age, ...}
/// </para>
/// <para>
/// ※ 若需自动完成所有相同属性的初始化操作,应写为 x => new Person {},而非 x => new Person()
/// </para>
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="TTargetEntity"></typeparam>
/// <param name="selector"></param>
/// <param name="tableName">指定插入的表名,若为 null 则使用 TTargetEntity 实体表名</param>
/// <param name="select">选择列</param>
/// <returns>返回影响的行数</returns>
public static int InsertIntoDiy<T1, TTargetEntity>(this ISelect<T1> selector, string tableName, Expression<Func<T1, TTargetEntity>> select) where TTargetEntity : class
{
return selector.InsertInto(tableName, AutoComplete(select));
}
/// <summary>
/// 生成自动补全相同属性的表达式树
/// </summary>
/// <typeparam name="TParam"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="exp"></param>
/// <returns></returns>
private static Expression<Func<TParam, TResult>> AutoComplete<TParam, TResult>(Expression<Func<TParam, TResult>> exp)
{
Expression node = exp.Body;
if (node.NodeType != ExpressionType.MemberInit) return exp;
MemberInitExpression initExp = node as MemberInitExpression;
IEnumerable<string> bindingNames = initExp.Bindings.Select(x => x.Member.Name);
ParameterExpression param = Expression.Parameter(typeof(TParam), exp.Parameters[0].Name);
PropertyInfo[] resultProps = typeof(TResult).GetProperties();
List<MemberBinding> bindings = new();
bindings.AddRange(initExp.Bindings);
foreach (PropertyInfo prop in typeof(TParam).GetProperties())
{
// 忽略已初始化的属性
if (bindingNames.Contains(prop.Name)) continue;
PropertyInfo resultProp = resultProps.FirstOrDefault(x => x.Name == prop.Name);
// 忽略TResult不存在的属性
if (resultProp == null) continue;
KeyAttribute keyAttr = resultProp.GetCustomAttribute<KeyAttribute>();
// 忽略Key属性
if (keyAttr != null) continue;
MemberExpression memberAccess = Expression.MakeMemberAccess(param, prop);
bindings.Add(Expression.Bind(resultProp, memberAccess));
}
MemberInitExpression body = initExp.Update(initExp.NewExpression, bindings);
return Expression.Lambda<Func<TParam, TResult>>(body, new ParameterExpression[] { param });
}