如何使用FastMember创建含子对象属性的IDataReader以实现SQLBulkCopy
解决FastMember ObjectReader包含嵌套对象属性的问题
这个场景我之前处理过,FastMember的ObjectReader默认只会读取顶层对象的属性,不会自动展开嵌套的子对象。不过有两种实用的办法能帮你把子对象的属性也纳入到IDataReader中:
方法一:显式指定嵌套属性路径
最直接的方式就是在创建ObjectReader时,用点语法明确写出嵌套对象的属性路径。如果数据库表的列名和嵌套属性路径不一致,还可以用别名来映射。
举个例子,假设你的记录类是这样的:
public class CustomerRecord { public int Id { get; set; } public string Name { get; set; } public AddressInfo Address { get; set; } } public class AddressInfo { public string Street { get; set; } public string City { get; set; } public string ZipCode { get; set; } }
情况1:数据库列名和属性路径一致
直接在ObjectReader.Create的参数里列出所有需要的属性:
using (var reader = ObjectReader.Create(customer.Records, "Id", "Name", "Address.Street", "Address.City", "Address.ZipCode")) { DataAccess.BulkInsert(serverName, databaseName, tableName, reader); }
情况2:数据库列名和属性路径不一致
用键值对来指定属性路径和对应的列别名:
using (var reader = ObjectReader.Create(customer.Records, // 顶层属性直接写名称 "Id", "Name", // 嵌套属性用KeyValuePair指定路径和别名 new KeyValuePair<string, string>("Address.Street", "Street"), new KeyValuePair<string, string>("Address.City", "City"), new KeyValuePair<string, string>("Address.ZipCode", "ZipCode"))) { DataAccess.BulkInsert(serverName, databaseName, tableName, reader); }
方法二:动态生成所有扁平化属性路径
如果嵌套对象的属性很多,不想手动一个个列出来,可以写个辅助方法,通过反射递归收集所有顶层和嵌套的属性路径,再传给ObjectReader。
辅助方法代码
using System.Reflection; private static IEnumerable<string> GetFlatPropertyPaths(Type targetType) { // 遍历所有公共实例属性 foreach (var property in targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { // 值类型或string直接返回属性名 if (property.PropertyType.IsValueType || property.PropertyType == typeof(string)) { yield return property.Name; } // 引用类型(排除string)则递归遍历子属性 else { foreach (var nestedPath in GetFlatPropertyPaths(property.PropertyType)) { yield return $"{property.Name}.{nestedPath}"; } } } }
使用方式
// 获取CustomerRecord所有扁平化的属性路径 var allPropertyPaths = GetFlatPropertyPaths(typeof(CustomerRecord)).ToArray(); using (var reader = ObjectReader.Create(customer.Records, allPropertyPaths)) { DataAccess.BulkInsert(serverName, databaseName, tableName, reader); }
注意事项
- FastMember会自动处理嵌套对象为
null的情况,此时对应的属性值会返回DBNull,不会抛出空引用异常。 - 如果有多层嵌套(比如
Address.Country.Name),点语法同样适用,辅助方法也会自动递归收集。 - 如果需要排除某些属性,在
GetFlatPropertyPaths方法里添加过滤逻辑即可(比如跳过特定名称的属性)。
内容的提问来源于stack exchange,提问作者Muds
相关产品推荐
相关产品推荐

