c# – CopyToDataTable:如果一个字段为NULL,为什么会抛出错误,
题:
我正在使用Linq.Dynamic的修改版本来根据ajax请求对数据表进行排序(请参阅下面的代码). 但是,我有一个问题: 如果我有一个包含NULL值的数据表,即使只有一行中的一个字段为NULL,我也会得到以下两个例外: Object must be of type "string" 如果几个相邻的值为NULL: At least one object must implement IComparable 这是我的代码 using System.Linq; using System.Data; using System.Linq.Dynamic; // Pre: // sidx: Sort Field // sord: Sort order ["ASC","DESC"] // page: current page number // rows: pagesize in rows public static string TestPaging(string sidx,string sord,string page,string rows) { string strReturnValue = null; using (System.Data.DataTable dtAllData = GetDataTable()) { IQueryable<System.Data.DataRow> iqOrderedPagedData = null; if (string.IsNullOrEmpty(sidx) || string.IsNullOrEmpty(sord)) iqOrderedPagedData = dtAllData.AsEnumerable().AsQueryable(); else iqOrderedPagedData = dtAllData.AsEnumerable().AsQueryable().OrderBy(sidx + " " + sord); Int32 iPageSize = string.IsNullOrEmpty(rows) ? 100 : System.Convert.ToInt32(rows); Int32 iPageIndex = System.Convert.ToInt32(page) - 1; iqOrderedPagedData = iqOrderedPagedData.Skip(iPageIndex * iPageSize).Take(iPageSize); //using (System.Data.DataTable dtOrderedPagedData = MyCopyToDataTable(iqOrderedPagedData)) using (System.Data.DataTable dtOrderedPagedData = iqOrderedPagedData.CopyToDataTable()) { cjqGrid jqGrid = new cjqGrid(); //jqGrid.total = dtAllData.Rows.Count / iPageSize + 1; jqGrid.total = (int)Math.Ceiling((float)dtAllData.Rows.Count / (float)iPageSize); jqGrid.page = iPageIndex + 1; jqGrid.records = dtAllData.Rows.Count; jqGrid.data = dtOrderedPagedData; strReturnValue = null; // Serialize(jqGrid,true); jqGrid = null; } // End Using dtOrderedPagedData } // End Using dtAllData //Response.ContentType = "application/json"; return strReturnValue; } TestPaging("USR_Domain","desc","1","10"); 问题似乎是扩展方法CopyToDataTable,在这一行: if (!e.MoveNext ()) 这使得它对表进行排序,这意味着它在类中调用函数Compare 在这一行抛出错误的地方 comparison = comparer.Compare(keys[first_index],keys[second_index]); 这里的单声道版本与我的修复程序,使单声道方法实际上工作. public static DataTable CopyToDataTable<T> (this IEnumerable<T> source) where T : DataRow { DataTable dt = new DataTable (); IEnumerator<T> e = source.GetEnumerator (); if (!e.MoveNext ()) throw new InvalidOperationException ("The source contains no DataRows"); foreach (DataColumn col in e.Current.Table.Columns) dt.Columns.Add (new DataColumn (col.ColumnName,col.DataType,col.Expression,col.ColumnMapping)); CopyToDataTable<T> (source,dt,LoadOption.PreserveChanges); return dt; } public static void CopyToDataTable<T> (this IEnumerable<T> source,DataTable table,LoadOption options) where T : DataRow { if (object.ReferenceEquals(typeof(T),typeof(System.Data.DataRow))) { foreach (System.Data.DataRow drRowToCopy in source) { System.Data.DataRow drNewRow = table.NewRow(); for (int i = 0; i < drRowToCopy.ItemArray.Length; ++i) { drNewRow[i] = drRowToCopy[i]; } // Next i table.Rows.Add(drNewRow); } // Next dr } else CopyToDataTable<T>(source,table,options,null); } 只要一行的一列中只有一个值为NULL,就会出现问题… 任何人都可以建议我如何解决这个问题? 现在我通过在比较中捕获异常来“修复”它. public override int Compare (int first_index,int second_index) { int comparison = 0; try { comparison = comparer.Compare(keys[first_index],keys[second_index]); } catch (Exception ex) { //Console.WriteLine(ex.Message); } if (comparison == 0) { if (child_context != null) return child_context.Compare (first_index,second_index); comparison = direction == SortDirection.Descending ? second_index - first_index : first_index - second_index; } return direction == SortDirection.Descending ? -comparison : comparison; } PS:对于我的DataTable-OrderBy-Enhanced版本的Linq.Dynamic,请看这里: 解决方法
好的,我得到了解决方案:
很明显它与System.DbNull类型有一些东西 首先,因为我的DataTable中只有字符串,并且收到了错误消息: Object must be of type "string" 但是字符串怎么可能不是字符串类型?当然只有它是DbNull. 如果你有两个相邻的DbNull.Values,你当然会得到: At least one object must implement IComparable 因为DbNull没有实现IComparable. 毕竟,有趣的是,当排序列是一个具有NULL值的列时,它只会失败,但如果它是一个没有NULL值的列,它确实可以正常工作. 由于表本身包含所有空值而不管顺序如何,因此CopyToDataTable有时不起作用是不合逻辑的,因为它每次都复制所有值而不管顺序如何. 唯一合乎逻辑的结论是OrderBy在代码中调用时不会被执行,但只有在某些方法实际使用OrderBy生成的数据时才会执行. 一个快速的谷歌搜索带我到这个 其中只需要读取前几行才能知道问题所在:
所以我突然意识到我刚刚通过通道权:) 显然缺点是e.MoveNext()在排序时触发了一个在DbNull上失败的比较,因为所说的DbNull没有实现IComparable. 具有讽刺意味的是,数据表也可以使用select语句进行排序,我最初并不知道(毕竟,我希望将“order”方法称为“order”,而不是“select”…) public static IQueryable OrderBy(this IQueryable source,string ordering,params object[] values) { if (source == null) throw new ArgumentNullException("source"); if (ordering == null) throw new ArgumentNullException("ordering"); if (object.ReferenceEquals(source.ElementType,typeof(System.Data.DataRow))) { using (DataTable dt = source.Cast<System.Data.DataRow>().CopyToDataTable()) { return dt.Select("",ordering).AsQueryable(); } 瞧,虫子消失了. 延迟执行是完全危险的,因为它会导致非常严重的可追踪错误.“boooom”所需要的只是在错误的地方的空值,或者缺少接口(以及缺少检查或缺少一般限制,如本例所示)… (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |