* DataTable的循环
1、DataTable的遍历
获得的值都是object类型,都需要先判断是否是DBNull.Value然后再转换
1、linq 语句
var result = from dr in dt.AsEnumerable() where !dr.IsNull("BookId") && int.Parse(dr.ItemArray[0].ToString()) == 3 select new { BookId = Convert.ToInt32(dr["BookId"]), Title = dr["Title"] };
2、for
for(int i=0; i<dt.Rows.Count; i++) { var c1 = dt.Rows[i]["BookId"] == DBNull.Value ? 0 : Convert.ToInt32(dt.Rows[i]["BookId"]) ; }
foreach(var item in dt.AsEnumerable()) { var c2 = item["BookId"]; var c3 = item["Title"]; }
可以用linq语法
2、DataTable的计算
var money = dt.AsEnumerable().Select(k => new //第一次select得到值 { f_money = Convert.ToDecimal(k["price"]), f_title = k["title"].ToString(), f_id = Convert.ToInt32(k["BookId"]), f_author = k["author"].ToString() }).GroupBy(k => k.f_author) //groupby进行了分组,得到的是一个key,对应一组value .Select(k => new { f_money = k.Sum(v => v.f_money), //分组之后这里只能用聚合函数 f_author = k.Key //得到key });
//添加统计数据 var allMoney = dtAllMoney.AsEnumerable().Select(k => new { f_name = isExcel == 1 ? LocalHelper.Lang("Font_meiritongji") : "<b><span style='color:blue'>" + LocalHelper.Lang("Font_meiritongji") + "</span></b>", f_bankId = "", f_money = Convert.ToDecimal(k["f_money"]), f_time = k["f_time"].ToString(), f_number = "", f_fee = dtAllMoney.Columns.Contains("f_fee") ? (k.IsNull("f_fee") ? 0 : Convert.ToDecimal(Math.Floor(Convert.ToDouble((Convert.ToDouble(k["f_fee"]) * 100).ToString())) / 100)) : 0 }).GroupBy(k => k.f_time).Select(k => new { f_name = k.Min(v => v.f_name), f_allMoney = k.Sum(v => v.f_money), f_allFee = k.Sum(v => v.f_fee), f_time = k.Key }).GroupBy(k => k.f_name); //进行循环 List<StatisticsModel> statisticsList2 = new List<StatisticsModel>(); foreach (var item in allMoney) { StatisticsModel tempeModel = new StatisticsModel(); tempeModel = item.Select(k => new StatisticsModel { f_sort = int.MinValue, f_name = item.Min(v => v.f_name), f_bankid = item.Key.ToString(), f_number = 0, f_allMoney = item.Sum(v => v.f_allMoney), f_allFee = item.Sum(v => v.f_allFee) }).FirstOrDefault(); decimal[] f_money = new decimal[2]; decimal[] f_fee = new decimal[2]; f_money[0] = item.Where(v => v.f_time == string.Concat(sYesteryear, "-", sYestermonths, sYesterday)).Sum(v => v.f_allMoney); f_money[1] = item.Where(v => v.f_time == string.Concat(year, "-", months, sThisDay)).Sum(v => v.f_allMoney); f_fee[0] = item.Where(v => v.f_time == string.Concat(sYesteryear, "-", sYestermonths, sYesterday)).Sum(v => v.f_allFee); f_fee[1] = item.Where(v => v.f_time == string.Concat(year, "-", months, sThisDay)).Sum(v => v.f_allFee); tempeModel.f_Money = f_money; tempeModel.f_Fee = f_fee; statisticsList2.Add(tempeModel); }
* DataTable、List、Enumerable比较
1、DataTable
DataTable dt = SqlHelper.ExecuteDataTable("select * from bookinfo", null); DataView dtview = dt.DefaultView; DataColumnCollection columns = dt.Columns; DataSet dset = dt.DataSet; dt.Merge(dt); //返回void类型 DataRow[] dtRows = dt.Select("bookid = 1");
2、List实现了IEnumerable接口
List实现了IEnumerable,可以用Enumerable类中的方法
是否支持foreach变量,必须满足2个条件:
1、实现IEnumerable接口;
2、这个类有一个public 的GetEnumerator的实例方法,并且返回类型IEnmerator具有public的bool MoveNext()方法和public的Current属性
IEnumerable 可迭代的,声明式的接口,没有具体实现如果迭代,仅有返回IEnumerator类型的方法;自定义类要使用foreach循环,就必须实现IEnumerable接口
[TypeDependencyAttribute("System.SZArrayHelper")] public interface IEnumerable<out T> : IEnumerable { // // 摘要: // 返回一个循环访问集合的枚举器。 // // 返回结果: // 用于循环访问集合的枚举数。 IEnumerator<T> GetEnumerator(); }
IEnumerator 迭代器,实现该接口就可以作为迭代器(iterator),包含了具体要实现的方法;
// // 摘要: // 支持对非泛型集合的简单迭代。 [ComVisible(true)] [Guid("496B0ABF-CDEE-11d3-88E8-00902754C43A")] public interface IEnumerator { // // 摘要: // 获取集合中位于枚举数当前位置的元素。 // // 返回结果: // 集合中位于枚举数当前位置的元素。 object Current { get; } // // 摘要: // 将枚举数推进到集合的下一个元素。 // // 返回结果: // 如果枚举数已成功地推进到下一个元素,则为 true;如果枚举数传递到集合的末尾,则为 false。 // // 异常: // T:System.InvalidOperationException: // 创建枚举器后,已修改该集合。 bool MoveNext(); // // 摘要: // 将枚举数设置为其初始位置,该位置位于集合中第一个元素之前。 // // 异常: // T:System.InvalidOperationException: // 创建枚举器后,已修改该集合。 void Reset(); }
DataTable dt = SqlHelper.ExecuteDataTable("select * from bookinfo", null); List<BookInfo> list = ConvertHelper<BookInfo>.ConvertToList(dt); bool isContainElement = list.Any(); //不包含时为false var k3 = list.Average(w => w.Price); var list1 = list.AsEnumerable(); var k2 = list1.Average(w => w.Price); var k4 = list1.Where(k => k.BookId == 1); var k1 = list1.Select(k => new { f_dd = k.Author });
3、linq语句
dt.Merge(dt2); //融合DataTable返回值为void var banks = from dr in dt.AsEnumerable() where !dr.IsNull("f_id") && !dr.IsNull("f_ShowName") select new { f_id = dr["f_id"].ToString(), f_name = dr["f_ShowName"].ToString() }; return Json(banks);
4、DataTable转为List
public static class ConvertHelper<T> where T : new() { /// <summary> /// DateTable 转List /// </summary> /// <param name="dt"></param> public static List<T> ConvertToList(DataTable dt) { List<T> list = new List<T>(); Type type = typeof(T); string tempName = string.Empty; foreach (DataRow dr in dt.Rows) { T t = new T(); //获得公共属性,利用反射获得属性 PropertyInfo[] propertys = t.GetType().GetProperties(); foreach (var it in propertys) { tempName = it.Name; //是否包含某一列 if (dt.Columns.Contains(tempName)) { if (!it.CanWrite) continue; object value = dr[tempName]; if (value != DBNull.Value) { //得到列的数据类型 string typ = it.GetGetMethod().ReturnType.Name.ToLower(); switch (typ) { case "int32": it.SetValue(t, Convert.ToInt32(value.ToString() == "" ? "0" : value) as object, null); break; case "double": it.SetValue(t, Convert.ToDouble(value.ToString() == "" ? "0" : value) as object, null); break; case "string": it.SetValue(t, value.ToString() as object, null); break; case "decimal": it.SetValue(t, Convert.ToDecimal(value.ToString() == "" ? "0" : value) as object, null); break; default: it.SetValue(t, value, null); break; } } } } list.Add(t); } return list; } }
* 常用
static void Main(string[] args) { DataTable dt = new DataTable(); dt.Columns.Add("Id"); //添加列 dt.Columns.Add("Name"); dt.Rows.Add("1", "刘备"); //添加行 dt.Rows.Add("2", "关羽"); dt.Rows.Add("3", "张飞"); dt.Rows.Add("4", "赵云"); dt.Rows.Add("5", "黄忠"); DataRow[] drArr = dt.Select("Id > 1 and Name <> '关羽'" ,"Id desc"); //条件支持and or like与SQL语句类似 //DataRow[] drArr2 = dt.Select("Name like '关%'", "Id desc"); //like示例 foreach(DataRow dr in drArr) { Console.WriteLine(dr["Name"]); //输出 黄忠 赵云 张飞 } Console.ReadKey(); }
static void Main(string[] args) { DataTable dt = new DataTable(); dt.Columns.Add("Id"); dt.Columns.Add("Name"); dt.Columns.Add("Age", typeof(Int32)); //注意要计算平均值要设置列类型为数字 dt.Rows.Add("1", "刘备", 31); dt.Rows.Add("2", "关羽", 29); dt.Rows.Add("3", "张飞", 28); dt.Rows.Add("4", "赵云", 27); dt.Rows.Add("5", "黄忠", 50); dt.DefaultView.Sort = "Age DESC"; //排序 dt = dt.DefaultView.ToTable(); //转换为DataTable foreach (DataRow dr in dt.Rows) { Console.WriteLine(dr["Name"]); } object obj = dt.Compute("Count(Id)", "Age>26"); //输出3 查询年龄大于26的人数 Console.WriteLine(obj.ToString()); object obj2 = dt.Compute("Avg(Age)", "true"); //输出33 查询所有人的平均年龄(要设置列为整型,否则不能计算) Console.WriteLine(obj2.ToString()); object obj3 = dt.Compute("Sum(Age)", "true"); //输出165 Console.WriteLine(obj3.ToString()); Console.ReadKey(); }
static void Main(string[] args) { DataTable dt = new DataTable(); DataColumn dc = dt.Columns.Add("Id", Type.GetType("System.Int32")); dc.AutoIncrement = true; //自动增加 dc.AutoIncrementSeed = 1; //起始为1 dc.AutoIncrementStep = 1; //步长为1 dc.AllowDBNull = false; //不允许为空 dt.Columns.Add("Name", Type.GetType("System.String")); dt.Columns.Add("Age", typeof(Int32)); //注意要计算平均值要设置列类型为数字 dt.Rows.Add(null,"刘备", 31); //注意这次添加不用在手输Id了,但是要给个null dt.Rows.Add(null,"关羽", 29); dt.Rows.Add(null,"张飞", 28); dt.Rows.Add(null,"赵云", 27); dt.Rows.Add(null, "黄忠", 50); foreach (DataRow dr in dt.Rows) { Console.WriteLine(dr["Id"]); //输出1 2 3 4 5 } Console.ReadKey(); }
1、System.DBNull
null在.Net中表示无效的对象引用。 即空对象。
DBNull是一个类(System.DBNull)。这个类直接继承于Object,它只有继承下来的属性与方法,只有一个自己的字段value。表示它自己。指数据库中数据为空(NULL)时,在.Net中的值。DBNull.Value表示一个对象在数据库中的值为空,或者说未初始化,DBNull.Value对象是指向有效的对象。
但是为什么 DBNull 可以表示数据库中的字符串,数字,或日期呢?原因是.Net储存这些数据的类(DataRow等)都是以 object 的形式来储存数据的。
对于 DataRow , 它的 row["column"] 返回的值永远不为null , 要么就是具体的为column的类型的值。要么就是DBNull 。 所以 row[column].ToString() 这个写法永远不会在ToString那里发生NullReferenceException,但有可能抛下标越界的异常。
DBNull 实现了 IConvertible 。 但是,除了 ToString 是正常的外,其他的ToXXX都会抛出不能转换的错误。
在 IDbCommand(OleDbCommand,SqlCommand...) 的ExecuteScalar的返回值中,情况可以这样分析:
SELECT 1 --这样返回的object是1。 SELECT null --这样返回的是DBNull.Value。
示例,假设在DataSet中我设置了一个int类型,但是在显示的时候,我想让为0的地方显示为空白该怎么实现呢?
static void Main(string[] args) { DataTable dt = new DataTable(); dt.Columns.Add("Name", typeof(String)); dt.Columns.Add("Age",typeof(Int32)); dt.Rows.Add("撼地神牛",0); dt.Rows.Add("刘备", 21); for (int i = 0; i < dt.Rows.Count; i++) { if (dt.Rows[i]["Age"].ToString() == "0") //注意DataRow返回的都是Object类型,需要自己转换为对应的类型 { //dt.Rows[i]["Age"] = null; 这样写会提示如下错误:不能将 Column“Age”设置为 null。请改用 DBNull。 dt.Rows[i]["Age"] = DBNull.Value; //用DBNull.Value; 在C#中显示空白,在数据库中显示null } Console.WriteLine(dt.Rows[i]["Name"] + ":" + dt.Rows[i]["Age"]); } Console.ReadKey(); }