C#中DataTable动态添加数据扩展方法空表问题排查
问题分析与解决方案
咱们先一步步排查问题,再给出优化后的可行代码:
1. 先排除调试器的“假象”
在Visual Studio调试窗口里,DataTable默认会显示为{},但这不代表它真的是空的。你得展开这个变量,查看Columns集合是否已经创建了对应AccessLevel的3列,再看Rows集合的数量是否和你传入的enumerable元素数一致。如果这两项都符合预期,那数据其实已经正确添加了,只是调试器的默认显示误导了你。
2. 代码里的性能隐患(虽不是空表直接原因,但必须优化)
你当前代码在循环里反复用Single(s2 => s2.Name.Equals(s))查找属性,每次都是O(n)的时间开销,完全没必要。咱们可以提前把属性名和PropertyInfo的映射用字典存起来,避免重复查找。
3. 确认传入的enumerable是否真的有数据
如果调用这个扩展方法时,传入的IEnumerable<AccessLevel>本身是空的(没有任何实例),那DataTable自然不会有行数据。可以在添加行之前加个判断,或者断点确认enumerable的元素数量。
优化后的完整代码
public static class ModelConverterToTVP { public static SqlMapper.ICustomQueryParameter AsTableValuedParameter<T>(this IEnumerable<T> enumerable, string typeName) { if (enumerable == null) throw new ArgumentNullException(nameof(enumerable)); if (string.IsNullOrEmpty(typeName)) throw new ArgumentNullException(nameof(typeName)); var dataTable = new DataTable(); // 筛选出可读的公共实例属性 var readableProperties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.CanRead) .ToList(); // 提前建立属性名到PropertyInfo的映射,避免重复查找 var propertyMap = readableProperties.ToDictionary(p => p.Name); // 为DataTable添加列,处理可空类型的情况 foreach (var prop in readableProperties) { // 如果是可空值类型,取其底层非空类型作为列类型 var columnType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType; dataTable.Columns.Add(prop.Name, columnType); } // 批量添加行数据 foreach (var obj in enumerable) { var rowValues = readableProperties.Select(prop => prop.GetValue(obj)).ToArray(); dataTable.Rows.Add(rowValues); } return dataTable.AsTableValuedParameter(typeName); } }
额外注意事项
- 要确保数据库里的**表值类型(TVP)**和你的
AccessLevel模型完全匹配:列名大小写一致、数据类型兼容、列顺序对应,否则即使DataTable有数据,也无法正确映射到TVP中,看起来像是“没有数据”。 - 代码里新增了对可空值类型的处理,如果你后续模型里用到
int?这类类型,也能正常生成对应列。
内容的提问来源于stack exchange,提问作者mr-dortaj
相关产品推荐
相关产品推荐

