【问题标题】:Generic Method to convert datatable to list将数据表转换为列表的通用方法
【发布时间】:2022-10-04 17:59:08
【问题描述】:

我正在使用以下代码:

 public static List<T> ConvertToList1<T>(DataTable dt)
        {
            var columnNames = dt.Columns.Cast<DataColumn>()
                    .Select(c => c.ColumnName)
                    .ToList();
            var properties = typeof(T).GetProperties();
            return dt.AsEnumerable().Select(row =>
            {
                T objT1 = Activator.CreateInstance<T>();
                foreach (var pro in properties)
                {
                    if (columnNames.Contains(pro.Name))
                    {
                        PropertyInfo? pI = objT.GetType().GetProperty(pro.Name);
                        pro.SetValue(objT, row[pro.Name] == DBNull.Value ? null : Convert.ChangeType(row[pro.Name], pI.PropertyType));

                    }
                }
                return objT1;
            }).ToList();
        }

但是对于具有空值的十进制字段,我收到错误消息。

从 'System.Decimal' 到 'System.Nullable`1[[System.Decimal, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral 的无效转换

 public class SampleModel
    {
        public Guid Id { get; set; }
        public Guid ProjectId { get; set; }
        public string? Code { get; set; } = null!;
        public string? Description { get; set; }
        public decimal? Quantity1 { get; set; }
        public decimal? Quantity2 { get; set; }
    }

谁能建议如何解决这个问题?

【问题讨论】:

标签: c# linq datatable


【解决方案1】:

嗯,再读一遍……你的意思是不能将行中的非空十进制值分配给可为空的小数?还是您的意思是不能分配给可空小数的 dbnull ?


您可以使用DataRow.IsNull 检查该值是否为 dbnull。在这种情况下,您只需跳过它,因为可空对象已经具有默认空值。

// <CODE SNIP />

if (columnNames.Contains(pro.Name))
{
    // if the value was null, just skip it.
    if(!row.IsNull(pro.Name))
    {
        PropertyInfo? pI = objT.GetType().GetProperty(pro.Name);
        pro.SetValue(objT, Convert.ChangeType(row[pro.Name], pI.PropertyType));
    }
}

【讨论】:

    【解决方案2】:

    尝试以下:

           public static List<SampleModel> ConvertToList1<T>(DataTable dt)
            {
                List<SampleModel> results = dt.AsEnumerable().Select(x => new SampleModel()
                {
                    Id = x.Field<Guid>("Id"),
                    ProjectId = x.Field<Guid>("ProjectId"),
                    Code = x.Field<string>("Code"),
                    Description = x.Field<string>("Description"),
                    Quantity1 = x.Field<decimal>("Quantity1"),
                    Quantity2 = x.Field<decimal>("Quantity1")
                }).ToList();
    
    
                return results;
            }
    

    【讨论】:

      【解决方案3】:

      我有戏。 @Ryan Wilson 的链接非常有用。

      简而言之,当您有一个可为空的类型时,您希望转换为基础类型。考虑:

      decimal? target;
      decimal source = 42;
      target = source;
      

      这是完全合理的代码。我们可以将decimal 值分配给decimal? 变量。

      如果myType 不可为空,则使用Nullable.GetUnderlyingType(myType) 返回一个类型或null。扩展上面的sn-p:

      var underlying1 = Nullable.GetUnderlyingType(target.GetType());
      var underlying2 = Nullable.GetUnderlyingType(source.GetType());
      

      这里,'underlying2' 是 'null','underlying1' 是 decimal

      然后,为了将其付诸实践,我们将转换方法的最里面部分稍微更改为:

      PropertyInfo pI = objT.GetType().GetProperty(pro.Name);
      var targetType = Nullable.GetUnderlyingType(pI.PropertyType) ?? pI.PropertyType;
      pro.SetValue(objT, row[pro.Name] == DBNull.Value 
        ? null
        : Convert.ChangeType(row[pro.Name], targetType));
      

      【讨论】:

        猜你喜欢
        • 2010-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-07
        相关资源
        最近更新 更多