首页 新闻 会员 周边 捐助

C# DataSet 序列化问题

0
悬赏园豆:50 [已解决问题] 解决于 2019-06-13 09:36

麻烦各位了,看有没有碰到过这个的,DataSet序列化报错,错误信息为:System.Runtime.Serialization.SerializationException:“内部数组不能扩展到大于 Int32.MaxValue 个元素。”
DataSet为包含30万条数据且列为180列的一张表,在进行序列化时报错,求解决方案,google,百度好久好像都说是C#的序列化BUG,麻爪中......,DataSet数据减少就算了,这是客户进行数据统计分析的一个操作,需要把大批量的数据全部加载并显示由客户进行处理,实际数据量可能比这个还要大,至于序列化是因为需要通过Remoting进行数据传输,将数据传到客户端减少流量消耗,以下代码是一简单Demo代码,同样会触发该BUG!

 

 1         static void Main(string[] args)
 2         {
 3             DataSet ds = new DataSet();
 4             DataTable dt = new DataTable();
 5             for (int i = 0; i < 180; i++)
 6             {
 7                 DataColumn dc = new DataColumn();
 8                 dc.ColumnName = "Column_" + i.ToString();
 9                 dc.DefaultValue = "Test_" + i.ToString();
10                 dt.Columns.Add(dc);
11             }
12             DateTime bft = DateTime.Now;
13             for (int i = 0; i < 300000; i++)
14             {
15                 DataRow dr = dt.NewRow();
16                 for (int j = 0; j < 180; j++)
17                 {
18                     dr[j] = "Row_" + i.ToString() + "_Column_" + j.ToString();
19                 }
20                 dt.Rows.Add(dr);
21             }
22             DateTime aft = DateTime.Now;
23             TimeSpan nspan = aft.Subtract(bft);
24             Console.WriteLine("添加300000条数据总共花费{0}ms.,{1}s,{2}m", nspan.TotalMilliseconds,nspan.TotalSeconds,nspan.TotalMinutes);
25             ds.Tables.Add(dt);
26             byte[] bArrayResult = null;
27             try
28             {
29                 ds.RemotingFormat = SerializationFormat.Binary;
30                 MemoryStream ms = new MemoryStream();
31                 IFormatter bf = new BinaryFormatter();
32                 bf.Serialize(ms, ds);
33                 bArrayResult = ms.ToArray();
34                 ms.Close();
35                 Console.WriteLine("DataSet文件大小:"+GetFileSize(bArrayResult.LongLength));
36             }
37             catch (Exception ex)
38             {
39                 throw ex;
40             }
41         }
42 
43         /// <summary>
44         /// 计算文件大小函数(保留两位小数),Size为字节大小
45         /// </summary>
46         /// <param name="size">初始文件大小</param>
47         /// <returns></returns>
48         public static string GetFileSize(long size)
49         {
50             var num = 1024.00; //byte
51             if (size < num)
52                 return size + "B";
53             if (size < Math.Pow(num, 2))
54                 return (size / num).ToString("f2") + "K"; //kb
55             if (size < Math.Pow(num, 3))
56                 return (size / Math.Pow(num, 2)).ToString("f2") + "M"; //M
57             if (size < Math.Pow(num, 4))
58                 return (size / Math.Pow(num, 3)).ToString("f2") + "G"; //G
59             return (size / Math.Pow(num, 4)).ToString("f2") + "T"; //T
60         }      
Sample Demo
问题补充:

有这问题的不止是DataSet序列化,转换为List或Hashtable序列化都是一样,只要数据列180左右行10万左右必定报这个错误!

sunkejava的主页 sunkejava | 初学一级 | 园豆:178
提问于:2019-06-07 12:38
< >
分享
最佳答案
1

/// <summary>
/// Table2Model
/// </summary>
public static class Table2Model {
#region 公共方法(扩展DataTable)

    /// <summary>
    ///  DataTable转换成T
    /// </summary>
    /// <typeparam name="T">实体类型</typeparam>
    /// <param name="table">需转换的数据table</param>
    /// <returns></returns>
    public static T ToModel<T>(this DataTable table) where T : new() {
        T entity = new T();

        foreach (DataRow row in table.Rows) {
            foreach (var item in entity.GetType().GetProperties()) {
                if (row.Table.Columns.Contains(item.Name)) {
                    if (DBNull.Value != row[item.Name]) {
                        item.SetValue(entity, ChangeType(row[item.Name], item.PropertyType), null);
                    }
                }
            }
        }

        return entity;
    }

    /// <summary>
    ///  DataTable转换成T
    /// </summary>
    /// <typeparam name="T">实体类型</typeparam>
    /// <param name="table">需转换的数据table</param>
    /// <param name="ext">外延表重名需加的前缀</param>
    /// <returns></returns>
    public static T ToModel<T>(this DataTable table, string ext) where T : new() {
        T entity = new T();

        foreach (DataRow row in table.Rows) {
            foreach (var item in entity.GetType().GetProperties()) {
                if (row.Table.Columns.Contains(ext + item.Name)) {
                    if (DBNull.Value != row[ext + item.Name]) {
                        item.SetValue(entity, ChangeType(row[ext + item.Name], item.PropertyType), null);
                    }
                }
            }
        }

        return entity;
    }

    /// <summary>
    ///  DataTable转换成List<T>
    /// </summary>
    /// <typeparam name="T">实体类型</typeparam>
    /// <param name="table">需转换的数据table</param>
    /// <returns></returns>
    public static List<T> ToModelList<T>(this DataTable table) where T : new() {
        List<T> entities = new List<T>();

        foreach (DataRow row in table.Rows) {
            T entity = new T();
            foreach (var item in entity.GetType().GetProperties()) {
                if (row.Table.Columns.Contains(item.Name)) {
                    if (DBNull.Value != row[item.Name]) {
                        item.SetValue(entity, ChangeType(row[item.Name], item.PropertyType), null);
                    }
                }
            }
            entities.Add(entity);
        }

        return entities;
    }

    #endregion 公共方法(扩展DataTable)

    #region 私有方法(Convert.ChangeType处理Nullable<>和非Nullable<>)

    /// <summary>
    /// 类型转换(包含Nullable<>和非Nullable<>转换)
    /// </summary>
    /// <param name="value"></param>
    /// <param name="conversionType"></param>
    /// <returns></returns>
    private static object ChangeType(object value, Type conversionType) {
        // Note: This if block was taken from Convert.ChangeType as is, and is needed here since we're
        // checking properties on conversionType below.
        if (conversionType == null) {
            throw new ArgumentNullException("conversionType");
        } // end if

        // If it's not a nullable type, just pass through the parameters to Convert.ChangeType

        if (conversionType.IsGenericType &&
          conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) {
            if (value == null) {
                return null;
            } // end if

            // It's a nullable type, and not null, so that means it can be converted to its underlying type,
            // so overwrite the passed-in conversion type with this underlying type
            System.ComponentModel.NullableConverter nullableConverter = new System.ComponentModel.NullableConverter(conversionType);

            conversionType = nullableConverter.UnderlyingType;
        } // end if

        // Now that we've guaranteed conversionType is something Convert.ChangeType can handle (i.e. not a
        // nullable type), pass the call on to Convert.ChangeType
        return Convert.ChangeType(value, conversionType);
    }

    #endregion 私有方法(Convert.ChangeType处理Nullable<>和非Nullable<>)
}

看看能够满足你要不

收获园豆:40
程序员修炼之旅 | 小虾三级 |园豆:976 | 2019-06-08 20:19

一样还是有问题,数据量只要到一定的大小还是会报错

sunkejava | 园豆:178 (初学一级) | 2019-06-09 13:49

@sunkejava: 如果是数据量过大,那么我建议你可以把dateset拆分一下,分别序列化以后,在合并为结果

程序员修炼之旅 | 园豆:976 (小虾三级) | 2019-06-09 15:05

不好搞啊,客户电脑内存太小,哪怕服务器端数据能查出来,分次也能传输到客户端,但是一合并就会造成溢出,没办法了只能减少列或者分页了,太坑了

sunkejava | 园豆:178 (初学一级) | 2019-06-13 09:32
其他回答(3)
0

你不是开玩笑吧,序列化 DataSet ?

dudu | 园豆:30948 (高人七级) | 2019-06-07 13:53

开啥玩笑,历史遗留所有数据全都是用DataSet接收处理的,要改其他的牵扯太大,不敢动

支持(0) 反对(0) sunkejava | 园豆:178 (初学一级) | 2019-06-07 14:55

@sunkejava: 是否可以尝试分页处理一下?

支持(0) 反对(0) 申龙斌的程序人生 | 园豆:207 (菜鸟二级) | 2019-06-08 08:50

@申龙斌的程序人生: 不行,这是一个客户进行前台统计分析操作的页面,需要加载出全部符合条件的数据进行统一分析

支持(0) 反对(0) sunkejava | 园豆:178 (初学一级) | 2019-06-08 11:39

@sunkejava: 那么大的数据量用户分析啥,不能下载吗?要在页面加载?

支持(0) 反对(0) 心雨纷扬 | 园豆:309 (菜鸟二级) | 2019-06-13 18:20
0

不能直接序列化 DataSet,要先保存成为文件:

/// <summary>
/// 序列和反序列 DataSet
/// </summary>
public static void SerializeDataSet()
{
    //测试数据
    DataSet ds = new DataSet();
    DataTable dt = GetTestData();
    ds.Tables.Add(dt);

    //序列化
    FileStream fs = new FileStream("ds.data", FileMode.Create);
    BinaryFormatter bf = new BinaryFormatter();
    ds.RemotingFormat = SerializationFormat.Binary;
    bf.Serialize(fs, ds);
    fs.Close();

    //清空 DataSet
    ds.Clear();
    fs = new FileStream("ds.data", FileMode.Open);

    //反序列化
    DataSet newDs = (DataSet)bf.Deserialize(fs);
}

/// <summary>
/// 获取测试数据
/// </summary>
/// <returns></returns>
private static DataTable GetTestData()
{
    DataTable dtTable = new DataTable();

    //建立字段
    dtTable.Columns.Add("filed1", typeof(int));
    dtTable.Columns.Add("filed2", typeof(string));
    dtTable.Columns.Add("filed3", typeof(bool));
    dtTable.Columns.Add("filed4", typeof(DateTime));

    DataRow row;
    for (int i = 1; i < 10; i++)//新增测试数据
    {
        row = dtTable.NewRow();
        row["filed1"] = i;
        row["filed2"] = "字符串" + i.ToString();
        row["filed3"] = i % 2 == 0;
        row["filed4"] = DateTime.Now;
        dtTable.Rows.Add(row);
    }

    return dtTable;
}
三人乐乐 | 园豆:4823 (老鸟四级) | 2019-06-07 14:38

测试了下,不行,你拿180列100000条左右的数据试下,还是会有那个提示

支持(0) 反对(0) sunkejava | 园豆:178 (初学一级) | 2019-06-07 21:29

@sunkejava: 不要用dataset,使用list

支持(0) 反对(0) 三人乐乐 | 园豆:4823 (老鸟四级) | 2019-06-12 09:35

@三人乐乐: 用过List了,结果一样,好像C#序列化超过一定大小之后就是会一直报这个错,除非数据量减少

支持(0) 反对(0) sunkejava | 园豆:178 (初学一级) | 2019-06-13 09:30
0

开个线程分页传输就好了,界面搞个提示框等待中,后台等全部传输完成一起展示,这样不管你有多少数据都没事

收获园豆:10
jqw2009 | 园豆:2341 (老鸟四级) | 2019-06-10 08:51
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册