如何为EF Core从实体对象编程生成MemberInitExpression供批量更新使用
错误点梳理
Expression.Bind第一个参数需传入属性对应的PropertyInfo实例,你当前传入的是属性的Get访问器方法,类型不匹配- 赋值的右值构造错误:你创建了无关联的新参数表达式,没有绑定到你实际要同步属性的目标User实例的值,EF Plus无法解析该表达式完成赋值
- 仅生成了
MemberInitExpression,没有封装为UpdateAsync要求的Expression<Func<User, User>>类型Lambda表达式
正确实现代码
// 这是你已有的、需要把属性值同步到数据库的User实例 User updatedUser = 你的User对象实例; Type userType = typeof(User); // 筛选需要更新的属性,可根据业务自行排除主键、自增字段、导航属性等不需要更新的字段 PropertyInfo[] props = userType.GetProperties() .Where(p => p.CanWrite && !new[] {"Id", "CreateTime"}.Contains(p.Name)) .ToArray(); // 构造Lambda的参数:x => ... 中的x ParameterExpression param = Expression.Parameter(userType, "x"); // 构造new User {} 的实例化表达式 NewExpression newUserExp = Expression.New(userType); List<MemberBinding> bindings = new List<MemberBinding>(); foreach (PropertyInfo prop in props) { // 从现有User实例中读取对应属性的实际值 object propValue = prop.GetValue(updatedUser); ConstantExpression valueExp = Expression.Constant(propValue, prop.PropertyType); // 绑定属性赋值逻辑 MemberBinding binding = Expression.Bind(prop, valueExp); bindings.Add(binding); } // 构造完整的成员初始化表达式 MemberInitExpression memberInit = Expression.MemberInit(newUserExp, bindings); // 封装为UpdateAsync需要的Lambda表达式 Expression<Func<User, User>> updateLambda = Expression.Lambda<Func<User, User>>(memberInit, param); // 执行更新 await _db.Users .Where(u => u.Username == updatedUser.Username) .UpdateAsync(updateLambda);
注意事项
- 生成属性列表时必须过滤不可修改的字段,避免出现更新主键、创建时间这类业务错误
- 如果需要适配所有实体类型,可以将上述逻辑封装为泛型扩展方法,后续新增实体或者实体新增属性都不需要调整更新逻辑
内容的提问来源于stack exchange,提问作者Fritz
相关产品推荐
相关产品推荐

