C#递归调用带类型变更的泛型方法实现EF批量插入关联子实体问题
错误根因
你触发报错的核心原因有2个:
- 你拿到的
childValueType不是实际的实体CLR类型:foreignKeyProperty.ToEndMember.GetEntityType()返回的是EF元数据体系下的System.Data.Entity.Core.Metadata.Edm.EntityType对象,你调用.GetType()拿到的是这个元数据对象本身的类型,不是你定义的子实体类的类型,自然不满足InsertAll的泛型约束。 - 你当前使用的
EFBatchOperation<TContext, T>实例是绑定了父实体类型T的,InsertAll方法要求泛型参数TEntity必须继承自T,但子实体类型几乎不可能符合这个约束,就算类型对了,你读的也是父实体的表映射,插入子实体也会报错。
修复步骤
1. 从EF元数据中获取子实体的真实CLR类型
// 替换原来获取childValueType的逻辑 var childClrType = (Type)childProperty.MetadataProperties["ClrType"].Value; // EF6及以上版本可以直接用内置属性 // var childClrType = childProperty.ClrType;
2. 构造对应子实体类型的EFBatchOperation实例,再递归调用
不能复用当前的this实例,需要根据子实体类型动态创建新的批量操作实例:
foreach (var foreignKeyProperty in foreignKeyProperties) { // 拿到子实体CLR类型 var childPropertyMetadata = foreignKeyProperty.ToEndMember.GetEntityType(); var childClrType = (Type)childPropertyMetadata.MetadataProperties["ClrType"].Value; foreach (var item in items) { // 拿到子集合值 var childValue = entityType.GetProperty(foreignKeyProperty.Name).GetValue(item); if (childValue == null) continue; // 构造子实体对应的EFBatchOperation实例 // 先获取对应子实体的DbSet var dbSetMethod = typeof(DbContext).GetMethod("Set", Type.EmptyTypes).MakeGenericMethod(childClrType); var childDbSet = dbSetMethod.Invoke(dbContext, null); // 调用EFBatchOperation.For方法创建实例 var forMethod = typeof(EFBatchOperation<,>).MakeGenericType(typeof(TContext), childClrType) .GetMethod("For", BindingFlags.Public | BindingFlags.Static, new[] { typeof(TContext), typeof(IDbSet<>).MakeGenericType(childClrType) }); var childBatchOperation = forMethod.Invoke(null, new[] { dbContext, childDbSet }); // 构造子实体对应的InsertAll泛型方法 var insertMethod = childBatchOperation.GetType().GetMethod("InsertAll").MakeGenericMethod(childClrType); // 调用插入,传入子集合、当前连接、批次大小 insertMethod.Invoke(childBatchOperation, new[] { childValue, connection, batchSize }); } }
额外注意事项
- 你需要确保批量插入父实体后自增主键已经回填到实体对象,否则子实体的外键字段会没有值,插入后关联关系失效。EntityFramework.Utilities的批量插入默认不开启ID回写,需要手动配置开启。
- 如果你的子实体还有嵌套的下级关联实体,递归逻辑会自动处理,不需要额外修改。
- 注意判断
childValue是否为null,避免空引用报错。
内容的提问来源于stack exchange,提问作者Mohamed Salah
相关产品推荐
相关产品推荐

