[英]Convert DataTable to IEnumerable<T>
我正在嘗試將 DataTable 轉換為 IEnumerable。 其中 T 是我創建的自定義類型。 我知道我可以通過創建List<T>
來做到這一點,但我在想是否有使用 IEnumerable 的更靈活的方法來做到這一點。 這是我現在所擁有的:
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();
}
關鍵部分是我正在創建一個List<T>
然后使用AsEnumerable()
返回它。
還有一個名為“AsEnumerable()”(在 System.Data 中)的 DataSetExtension 方法,它接受一個 DataTable 並返回一個 Enumerable。 有關更多詳細信息,請參閱MSDN 文檔,但它基本上與以下內容一樣簡單:
dataTable.AsEnumerable()
缺點是它正在枚舉 DataRow,而不是您的自定義類。 “Select()”LINQ 調用可以轉換行數據,但是:
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"]),
});
}
該實現沒有任何問題。 你可以試試yield
關鍵字,看看你喜歡它:
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"]),
};
}
}
也不需要AsEnumerable
,因為List<T>
已經是一個IEnumerable<T>
使用System.Data.DataSetExtensions
簡單方法:
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"]),
});
或者:
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));
或者,更好的是,創建一個TankReading(DataRow r)
構造函數,然后變成:
table.AsEnumerable().Select(row => return new TankReading(row));
如果您從 SQL 查詢生成DataTable
,您是否考慮過簡單地使用 Dapper?
然后,而不是使用SqlParameters
和DataTable
以及DataAdapter
等等制作SqlCommand
,然后您必須費力地將其轉換為類,您只需定義類,使查詢列名稱與字段名稱匹配,並且參數很容易被名字綁定。 您已經定義了TankReading
類,所以它會非常簡單!
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 非常優化,可以為您提供與直接使用DataAdapter
讀取幾乎相同的性能。
如果您的類中有任何邏輯,或者是不可變的或沒有無參數構造函數,那么您可能確實需要有一個DbTankReading
類(作為純 POCO/Plain Old Class Object):
// 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; }
}
你會像這樣使用它:
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
});
盡管有映射工作,但這仍然沒有數據表方法那么痛苦。 這也允許您執行某種邏輯,但如果邏輯不僅僅是非常簡單的直接映射,我會將邏輯放入單獨的TankReadingMapper
類中。
如果要將任何 DataTable 轉換為等效的 IEnumerable 向量函數。
請查看以下通用函數,這可能會幫助您的需求(您可能需要根據您的需要包含不同數據類型的寫案例)。
/// <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();
}
DataTable 的通用擴展方法。 可能有人很有趣。 我從另一篇文章中獲取的創建動態屬性的想法: https : //stackoverflow.com/a/15819760/8105226
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;
}
}
}
我在這里寫了一篇關於這個主題的文章。 我想它可以幫助你。
通常它會做這樣的事情:
static void Main(string[] args)
{
// Convert from a DataTable source to an IEnumerable.
var usersSourceDataTable = CreateMockUserDataTable();
var usersConvertedList = usersSourceDataTable.ToEnumerable<User>();
// Convert from an IEnumerable source to a DataTable.
var usersSourceList = CreateMockUserList();
var usersConvertedDataTable = usersSourceList.ToDataTable<User>();
}
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;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.