EF Core批量操作扩展中如何向泛型方法传递指定类型属性列表
实现方案
你不需要自定义TProperty,也不用强制传入IProperty实例,基于Lambda表达式的类型安全方案完全可以满足需求,和EF Core原生API的使用习惯一致,学习成本很低:
1. 调整方法签名
直接用Expression<Func<T, object>>作为参数类型,天然限定了只能传入T类型的属性,编译期就能做校验,不会出现运行时属性名写错的问题:
public static void BulkInsertOrUpdate<T>( this DbContext ctx, List<T> list, Expression<Func<T, object>>[] columnsToMatch, Expression<Func<T, object>>[] columnsToUpdate, bool identityInsert = false, int batchSize = 1000) where T : class
如果要兼容更灵活的传参习惯,也可以把数组改成params Expression<Func<T, object>>[],调用时不需要手动包裹数组。
2. 解析表达式获取属性元数据
写个辅助方法从Lambda表达式中提取EF Core的IProperty元数据,供你后续生成合并SQL(比如MERGE语句或者数据库原生的UPSERT语法)使用:
private static IProperty ResolveProperty<T>(Expression<Func<T, object>> expr, DbContext ctx) where T : class { // 处理值类型属性自动装箱的UnaryExpression var memberExpr = expr.Body switch { UnaryExpression unary when unary.Operand is MemberExpression me => me, MemberExpression me => me, _ => throw new ArgumentException("仅支持指向实体属性的Lambda表达式") }; var propInfo = memberExpr.Member as PropertyInfo; if (propInfo == null) throw new ArgumentException("表达式必须指向实体的公共属性"); // 从EF Core模型中获取对应的IProperty元数据 var entityType = ctx.Model.FindEntityType(typeof(T)); var efProp = entityType?.FindProperty(propInfo); return efProp ?? throw new ArgumentException($"属性{propInfo.Name}不是类型{typeof(T).Name}的EF Core映射属性"); }
方法内部遍历传入的columnsToMatch和columnsToUpdate数组,调用上述方法就能拿到所有需要的IProperty实例。
3. 调用示例
调用方式非常简洁,和EF Core原生的Include、OrderBy等方法的用法完全一致:
fooDbContext.BulkInsertOrUpdate( listOfPersonRecords, [p => p.FirstName, p => p.LastName, p => p.DateOfBirth], [p => p.Address, p => p.City, p => p.State, p => p.Zip]);
低版本C#不支持集合表达式的话,把[]换成new [] { }即可。
注:你之前设想的传IProperty的方案可用性很低,因为IProperty是EF Core内部的模型元数据,普通开发者调用接口时没法直接通过
Person.FirstName的方式获取,需要先从DbContext的模型元数据中查询,使用成本极高,完全不如Lambda表达式的方案友好。
内容的提问来源于stack exchange,提问作者CMGeek
相关产品推荐
相关产品推荐

