Convert DataTable to IEnumerable<T>
我正在尝试将数据表转换为IEnumerable。其中t是我创建的自定义类型。我知道我可以通过创建一个列表来完成它,但我认为有一种更巧妙的方法可以使用IEnumerable来完成它。这是我现在拥有的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | private IEnumerable<TankReading> ConvertToTankReadings(DataTable dataTable) { var tankReadings = new List<TankReading>(); foreach (DataRow row in dataTable.Rows) { var tankReading = new TankReading { TankReadingsID = Convert.ToInt32(row["TRReadingsID"]), TankID = Convert.ToInt32(row["TankID"]), ReadingDateTime = Convert.ToDateTime(row["ReadingDateTime"]), ReadingFeet = Convert.ToInt32(row["ReadingFeet"]), ReadingInches = Convert.ToInt32(row["ReadingInches"]), MaterialNumber = row["MaterialNumber"].ToString(), EnteredBy = row["EnteredBy"].ToString(), ReadingPounds = Convert.ToDecimal(row["ReadingPounds"]), MaterialID = Convert.ToInt32(row["MaterialID"]), Submitted = Convert.ToBoolean(row["Submitted"]), }; tankReadings.Add(tankReading); } return tankReadings.AsEnumerable(); } |
关键部分是我正在创建一个列表,然后使用aseNumerable()返回它。
还有一个名为"AsEnumerable()(在System.Data中)的DataSetExtension方法,它获取一个DataTable并返回一个Enumerable。有关更多详细信息,请参阅msdn文档,但它基本上很简单:
1 | dataTable.AsEnumerable() |
缺点是它正在枚举数据行,而不是您的自定义类。"select()"LINQ调用可以转换行数据,但是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | private IEnumerable<TankReading> ConvertToTankReadings(DataTable dataTable) { return dataTable.AsEnumerable().Select(row => new TankReading { TankReadingsID = Convert.ToInt32(row["TRReadingsID"]), TankID = Convert.ToInt32(row["TankID"]), ReadingDateTime = Convert.ToDateTime(row["ReadingDateTime"]), ReadingFeet = Convert.ToInt32(row["ReadingFeet"]), ReadingInches = Convert.ToInt32(row["ReadingInches"]), MaterialNumber = row["MaterialNumber"].ToString(), EnteredBy = row["EnteredBy"].ToString(), ReadingPounds = Convert.ToDecimal(row["ReadingPounds"]), MaterialID = Convert.ToInt32(row["MaterialID"]), Submitted = Convert.ToBoolean(row["Submitted"]), }); } |
这个实现没有任何错误。你可以给
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | private IEnumerable<TankReading> ConvertToTankReadings(DataTable dataTable) { foreach (DataRow row in dataTable.Rows) { yield return new TankReading { TankReadingsID = Convert.ToInt32(row["TRReadingsID"]), TankID = Convert.ToInt32(row["TankID"]), ReadingDateTime = Convert.ToDateTime(row["ReadingDateTime"]), ReadingFeet = Convert.ToInt32(row["ReadingFeet"]), ReadingInches = Convert.ToInt32(row["ReadingInches"]), MaterialNumber = row["MaterialNumber"].ToString(), EnteredBy = row["EnteredBy"].ToString(), ReadingPounds = Convert.ToDecimal(row["ReadingPounds"]), MaterialID = Convert.ToInt32(row["MaterialID"]), Submitted = Convert.ToBoolean(row["Submitted"]), }; } } |
也不需要
如果您是从SQL查询生成
然后,不需要用
1 2 3 4 5 6 7 8 9 | using Dapper; // Below can be SqlConnection cast to DatabaseConnection, too. DatabaseConnection connection = // whatever IEnumerable<TankReading> tankReadings = connection.Query<TankReading>( "SELECT * from TankReading WHERE Value = @value", new { value ="tank1" } // note how `value` maps to `@value` ); return tankReadings; |
现在不是太棒了吗?dapper是非常优化的,它将为您提供与直接使用
如果您的类中有任何逻辑,或者是不可变的,或者没有无参数的构造函数,那么您可能需要一个
1 2 3 4 5 6 7 8 9 10 11 12 | // internal because it should only be used in the data source project and not elsewhere internal sealed class DbTankReading { int TankReadingsID { get; set; } DateTime? ReadingDateTime { get; set; } int ReadingFeet { get; set; } int ReadingInches { get; set; } string MaterialNumber { get; set; } string EnteredBy { get; set; } decimal ReadingPounds { get; set; } int MaterialID { get; set; } bool Submitted { get; set; } } |
你可以这样使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | IEnumerable<TankReading> tankReadings = connection .Query<DbTankReading>( "SELECT * from TankReading WHERE Value = @value", new { value ="tank1" } // note how `value` maps to `@value` ) .Select(tr => new TankReading( tr.TankReadingsID, tr.ReadingDateTime, tr.ReadingFeet, tr.ReadingInches, tr.MaterialNumber, tr.EnteredBy, tr.ReadingPounds, tr.MaterialID, tr.Submitted }); |
尽管进行了映射工作,但与数据表方法相比,这仍然不那么痛苦。这也允许您执行某种逻辑,但是如果逻辑不仅仅是简单的直接交叉映射,那么我将把逻辑放到单独的
使用
1 2 3 4 5 6 7 8 9 10 11 12 | table.AsEnumerable().Select(row => new TankReading{ TankReadingsID = Convert.ToInt32(row["TRReadingsID"]), TankID = Convert.ToInt32(row["TankID"]), ReadingDateTime = Convert.ToDateTime(row["ReadingDateTime"]), ReadingFeet = Convert.ToInt32(row["ReadingFeet"]), ReadingInches = Convert.ToInt32(row["ReadingInches"]), MaterialNumber = row["MaterialNumber"].ToString(), EnteredBy = row["EnteredBy"].ToString(), ReadingPounds = Convert.ToDecimal(row["ReadingPounds"]), MaterialID = Convert.ToInt32(row["MaterialID"]), Submitted = Convert.ToBoolean(row["Submitted"]), }); |
或:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | TankReading TankReadingFromDataRow(DataRow row){ return new TankReading{ TankReadingsID = Convert.ToInt32(row["TRReadingsID"]), TankID = Convert.ToInt32(row["TankID"]), ReadingDateTime = Convert.ToDateTime(row["ReadingDateTime"]), ReadingFeet = Convert.ToInt32(row["ReadingFeet"]), ReadingInches = Convert.ToInt32(row["ReadingInches"]), MaterialNumber = row["MaterialNumber"].ToString(), EnteredBy = row["EnteredBy"].ToString(), ReadingPounds = Convert.ToDecimal(row["ReadingPounds"]), MaterialID = Convert.ToInt32(row["MaterialID"]), Submitted = Convert.ToBoolean(row["Submitted"]), }; } // Now you can do this table.AsEnumerable().Select(row => return TankReadingFromDataRow(row)); |
或者,更好的是,创建一个
1 |
如果要将任何数据表转换为等效的IEnumerable向量函数。
请看一下下面的通用函数,这可能有助于您的需求(您可能需要根据需要包括不同数据类型的写案例)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | /// <summary> /// Get entities from DataTable /// </summary> /// <typeparam name="T">Type of entity</typeparam> /// <param name="dt">DataTable</param> /// <returns></returns> public IEnumerable<T> GetEntities<T>(DataTable dt) { if (dt == null) { return null; } List<T> returnValue = new List<T>(); List<string> typeProperties = new List<string>(); T typeInstance = Activator.CreateInstance<T>(); foreach (DataColumn column in dt.Columns) { var prop = typeInstance.GetType().GetProperty(column.ColumnName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public); if (prop != null) { typeProperties.Add(column.ColumnName); } } foreach (DataRow row in dt.Rows) { T entity = Activator.CreateInstance<T>(); foreach (var propertyName in typeProperties) { if (row[propertyName] != DBNull.Value) { string str = row[propertyName].GetType().FullName; if (entity.GetType().GetProperty(propertyName).PropertyType == typeof(System.String)) { object Val = row[propertyName].ToString(); entity.GetType().GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public).SetValue(entity, Val, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, null, null); } else if (entity.GetType().GetProperty(propertyName).PropertyType == typeof(System.Guid)) { object Val = Guid.Parse(row[propertyName].ToString()); entity.GetType().GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public).SetValue(entity, Val, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, null, null); } else { entity.GetType().GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public).SetValue(entity, row[propertyName], BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, null, null); } } else { entity.GetType().GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public).SetValue(entity, null, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, null, null); } } returnValue.Add(entity); } return returnValue.AsEnumerable(); } |
数据表的通用扩展方法。可能是某个有趣的人。我从另一篇文章中获得了创建动态属性的想法:https://stackoverflow.com/a/15819760/8105226
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | public static IEnumerable<dynamic> AsEnumerable(this DataTable dt) { List<dynamic> result = new List<dynamic>(); Dictionary<string, object> d; foreach (DataRow dr in dt.Rows) { d = new Dictionary<string, object>(); foreach (DataColumn dc in dt.Columns) d.Add(dc.ColumnName, dr[dc]); result.Add(GetDynamicObject(d)); } return result.AsEnumerable<dynamic>(); } public static dynamic GetDynamicObject(Dictionary<string, object> properties) { return new MyDynObject(properties); } public sealed class MyDynObject : DynamicObject { private readonly Dictionary<string, object> _properties; public MyDynObject(Dictionary<string, object> properties) { _properties = properties; } public override IEnumerable<string> GetDynamicMemberNames() { return _properties.Keys; } public override bool TryGetMember(GetMemberBinder binder, out object result) { if (_properties.ContainsKey(binder.Name)) { result = _properties[binder.Name]; return true; } else { result = null; return false; } } public override bool TrySetMember(SetMemberBinder binder, object value) { if (_properties.ContainsKey(binder.Name)) { _properties[binder.Name] = value; return true; } else { return false; } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | PagedDataSource objPage = new PagedDataSource(); DataView dataView = listData.DefaultView; objPage.AllowPaging = true; objPage.DataSource = dataView; objPage.PageSize = PageSize; TotalPages = objPage.PageCount; objPage.CurrentPageIndex = CurrentPage - 1; //Convert PagedDataSource to DataTable System.Collections.IEnumerator pagedData = objPage.GetEnumerator(); DataTable filteredData = new DataTable(); bool flagToCopyDTStruct = false; while (pagedData.MoveNext()) { DataRowView rowView = (DataRowView)pagedData.Current; if (!flagToCopyDTStruct) { filteredData = rowView.Row.Table.Clone(); flagToCopyDTStruct = true; } filteredData.LoadDataRow(rowView.Row.ItemArray, true); } //Here is your filtered DataTable return filterData; |