数据集在导出时不支持System.Nullable<>。

70

我试图使用导出到Excel、PDF、文本文件的方式生成报告。在MVC中进行此操作。我有一个类,我将其命名为SPBatch(这是我的SQL存储过程的确切名称),其中包含以下内容:

public string BatchNo { get; set; }
public string ProviderName { get; set; }
public Nullable<System.Int32> NoOfClaims { get; set; }
public Nullable<System.Int32> TotalNoOfClaims { get; set; }
public Nullable<System.Decimal> TotalBilled { get; set; }
public Nullable<System.Decimal> TotalInputtedBill { get; set; }
public Nullable<System.DateTime> DateCreated { get; set; }
public Nullable<System.DateTime> DateSubmitted { get; set; }
public Nullable<System.DateTime> DueDate { get; set; }
public string Status { get; set; }
public string RefNo { get; set; }
public string BatchStatus { get; set; }
public string ClaimType { get; set; }

正如您所看到的,我的某些列被声明为可为空。从搜索并在表格中显示结果顺利进行。我在下方有几个按钮,它们是用于导出的图像按钮,但每次尝试导出 Excel 时,我总是在代码的这一部分遇到问题 "DataSet does not support System.Nullable<>"。

foreach (MemberInfo mi in miArray)
{
    if (mi.MemberType == MemberTypes.Property)
    {
        PropertyInfo pi = mi as PropertyInfo;
        dt.Columns.Add(pi.Name, pi.PropertyType); //where the error pop's up.

    }
    else if (mi.MemberType == MemberTypes.Field)
    {
        FieldInfo fi = mi as FieldInfo;
        dt.Columns.Add(fi.Name, fi.FieldType);
    }
}

这个错误出现在有评论的那个上面。你能帮助我该怎么做吗?我尝试在我的代码中添加DBNull,但仍然得到相同的错误。我尝试从我的SPBatch中移除Nullable,但是我得到一个错误,说需要将某些表声明为Nullable。

我应该怎么办?


我建议不要使用 DataSet,因为它似乎不支持您的需求。 - John Saunders
4个回答

174

尝试使用

dt.Columns.Add(pi.Name, Nullable.GetUnderlyingType(
            pi.PropertyType) ?? pi.PropertyType);

1
我尝试了一下,但是在Columns[column].SetOrdinal(Index);这行代码中出现了错误"对象引用未设置到对象的实例"。 - Ms. B
2
我在你的问题代码示例中找不到这样的代码! - Damith
1
在这边很好 public void SetColumn(string column, string columnName) { Columns[column].SetOrdinal(Index); //这里 Columns[column].ColumnName = columnName; Index++; } - Ms. B
3
请就应用程序中的其他问题提出不同的问题。 - Damith
1
无论如何,我已经解决了这个问题,你的代码现在运行良好。非常感谢你。 - Ms. B

5

感谢 C# 版本的生成数据表以及一些技巧,我可以提供 VB 的答案 - 我把它放在这里是因为我刚刚遇到了很多麻烦,想要从一个存储过程中获取可过滤的数据集,同时使用简单的数据层。我希望它能帮助其他人!

注意:使用情况是您希望使用 BindingSource.Filter =“某个查询字符串”:

Imports System.Reflection

Public Module Extenders
<System.Runtime.CompilerServices.Extension>
Public Function ToDataTable(Of T)(collection As IEnumerable(Of T), tableName As String) As DataTable
    Dim tbl As DataTable = ToDataTable(collection)
    tbl.TableName = tableName
    Return tbl
End Function

<System.Runtime.CompilerServices.Extension>
Public Function ToDataTable(Of T)(collection As IEnumerable(Of T)) As DataTable
    Dim dt As New DataTable()

    Dim tt As Type = GetType(T)
    Dim pia As PropertyInfo() = tt.GetProperties()

    'Create the columns in the DataTable

    For Each pi As PropertyInfo In pia
        Dim a = 
If(Nullable.GetUnderlyingType(pi.PropertyType), pi.PropertyType)
        dt.Columns.Add(pi.Name, If(Nullable.GetUnderlyingType(pi.PropertyType), pi.PropertyType))
    Next

    'Populate the table

    For Each item As T In collection
        Dim dr As DataRow = dt.NewRow()
        dr.BeginEdit()

        For Each pi As PropertyInfo In pia

            dr(pi.Name) = If(Nullable.GetUnderlyingType(pi.PropertyType) Is GetType(DateTime), DBNull.Value, pi.GetValue(item, Nothing))
        Next
        dr.EndEdit()
        dt.Rows.Add(dr)
    Next
    Return dt
End Function

End Module

1
这太棒了。正是我所需要的。我做了一个小改变,可能对其他人有用... dr(pi.Name) = If(pi.GetValue(item, Nothing), DBNull.Value) 这似乎使它与可空日期更好地配合使用。 - user1751825

1
我会搜索 nullable 并将其替换为一个可以为空的字符串,而不是 DateTime。
foreach (PropertyInfo pi in properties)
{
    if (pi.PropertyType.Name.Contains("Nullable"))
       myDataType = typeof(String);
    else
       myDataType = pi.PropertyType;
}

这里是完整版:
private DataTable CreateDataTable(PropertyInfo[] properties)
{
    DataTable dt = new DataTable();
    DataColumn dc = null;
    foreach (PropertyInfo pi in properties)
    {
        dc = new DataColumn();
        dc.ColumnName = pi.Name;

        if (pi.PropertyType.Name.Contains("Nullable"))
            dc.DataType = typeof(String);
        else
            dc.DataType = pi.PropertyType;

        // dc.DataType = pi.PropertyType;
        dt.Columns.Add(dc);
    }
    return dt;
}

2
那么,如果底层数据在特定行中包含DateTime类型的数据呢? - John Saunders
1
一个没有值的可空 DateTime 在 Excel 端会被转换为 NULL。 - Ross Bush
1
实际上,我看到dasmith添加的答案更优雅。 - Ross Bush
1
它将如何在“DataSet”中显示? - John Saunders
作为一个字符串,它会出现。 - Ross Bush
显示剩余2条评论

1

1)将此扩展定义如下:

public static class ListExtensions
    {
        public static DataTable ToDataTable<T>(this List<T> list)
        {
            DataTable table = new DataTable(typeof(T).Name);

            //Get Properites of List Fiels
            PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

            //Create Columns as Fields of List
            foreach (PropertyInfo propertyInfo in props)
            {
                var column = new DataColumn
                {
                    ColumnName = propertyInfo.Name,
                    DataType = propertyInfo.PropertyType.Name.Contains("Nullable") ? typeof(string) : propertyInfo.PropertyType
                };

                table.Columns.Add(column);
            }

            //Fill DataTable with Rows of List
            foreach (var item in list)
            {
                var values = new object[props.Length];

                for (var i = 0; i < props.Length; i++)
                {
                    values[i] = props[i].GetValue(item, null);
                }

                table.Rows.Add(values);
            }


            return table;
        }
    }

2) 以下是调用扩展方法的方式,其中[_lstOperationDetails]是我们想要将其从List转换为DataTable的列表

DataTable operationDetails = _lstOperationDetails.ToDataTable();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接