如何使用 LINQ 从 DataTable 中以 IEnumerable<MODEL> 形式获取数据?
Posted
技术标签:
【中文标题】如何使用 LINQ 从 DataTable 中以 IEnumerable<MODEL> 形式获取数据?【英文标题】:How to get data as IEnumerable<MODEL> from DataTable by using LINQ? 【发布时间】:2020-12-08 11:21:19 【问题描述】:我有一个DataTable
,其中一些属性数据来自数据库,DataTable
中的每个数据都属于一个产品,每个产品可以有多个属性。
所以我有另一个DataTable
,它在foreach
中包含所有产品,通过循环遍历每一行,我将每个产品添加到List<Plu>
,如下所示:
var productAttr = new List<Plu.Attributi>();
foreach (DataRow rowPlu in dt.Rows)
try
int id = (int)rowPlu["ID_PLUREP"];
plu.Add(new Plu(
id,
(string)rowPlu["CODICE_PRP"],
(string)rowPlu[ESTESA],
(string)rowPlu[DESCR], (float)rowPlu["PRE_PRP"],
rowPlu.IsNull("IMG_IMG") ? null : (string)rowPlu["IMG_IMG"],
productAttr,
null,
(int)rowPlu["ID_MENU_PRP"]
));
catch
return plu;
现在productAttr
是空的,但现在我需要将它的属性添加到每个产品中,所以通过以下函数我得到一个DataTable
,其中填充了数据库中包含所有产品属性的数据:
var attributi = Attributi(connection, idNegozio);
然后我试图在foreach
中做这样的事情
foreach (DataRow rowPlu in dt.Rows)
try
int id = (int)rowPlu["ID_PLUREP"];
plu.Add(new Plu(
id,
(string)rowPlu["CODICE_PRP"],
(string)rowPlu[ESTESA],
(string)rowPlu[DESCR], (float)rowPlu["PRE_PRP"],
rowPlu.IsNull("IMG_IMG") ? null : (string)rowPlu["IMG_IMG"],
from row in attributi.AsEnumerable() where row.Field<int>("ID_PLUREP_VAT") == id select row,
null,
(int)rowPlu["ID_MENU_PRP"]
));
catch
return plu;
但是 LINQ 返回一个EnumerableRowCollection
而我需要一个IEnumerable<Plu.Attribute>
,所以我想知道是否有一种懒惰的方式将.AsEnumerable
转换为IEnumerable<Plu.Attrbute>
...
【问题讨论】:
.Cast<Plu.Attrbute>()
?
【参考方案1】:
问题是,DataTable 只知道单元格中的值。它不知道这些值代表什么。它不知道第 0 列中的数字实际上是一个 Id。它不知道第 1 列中的字符串是客户的姓名,而第 2 列中的 DateTime 是客户的生日。
如果您将来要将此 Datatable(或类似 DataTables)的内容用于其他查询,则需要从 DataRow 转换为它们所代表的项目。
在完成从 DataRow 到 Plu 的转换后,您可以将 DataTable 转换为 IEnumerable<Plu>
,并对其进行其他 LINQ 处理。
用法如下:
DataTable table = ...
var mySelectedData = table.AsEnumerable().ToPlus()
.Where(plu => ...)
.Select(plu => new ...)
.ToList();
您需要两种扩展方法:一种将 DataRow 转换为 Plu,另一种将 DataRow 序列转换为 Plus 序列。见extension methods demystified
public static Plu ToPlu(this DataRow row)
// TODO implement
public static IEnumerable<Plu> ToPlus(this IEnumerable<DataRow> dataRows)
// TODO: exception if null dataRows
return dataRows.Select(row => row.ToPlu());
如果需要,从 DataTable 创建一个扩展方法来提取 Plus:
public static IEnumerable<Plu> ExtractPlus(this DataTable table)
// TODO: exception if table null
return table.AsEnumerable().ToPlus();
用法:
DataTable table = ...
IEnumerable<Plu> plus = table.ExtractPlus();
我对 Plu 是什么一无所知,而且您忘记提及 Plu 的相关属性,所以我将给您举一个包含客户的表的示例:
class Customer
public int Id get; set; // Id will be in column 0
public string Name get; set; // Name will be in column 1
...
public static Customer ToCustomer(this DataRow row)
return new Customer
Id = (int)row[0],
Name = (string)row[1],
;
如果需要,您可以使用列名代替 columnIndex。
因此,只需创建一个ToPlu
和一个将 DataRows 序列转换为 Plus 序列的单行方法,您就可以使用读取表的方法扩展 LINQ。
为了安全起见,请考虑创建一个将 Plus 序列转换为 DataTable 的扩展方法。这样,表格的布局就在一个位置:ToPlu(DataRow)
和 ToDataRow(Plu)
。表格布局的未来变化将更易于管理,您的 DataTable 的用户只会考虑 Plus 的序列。
【讨论】:
【参考方案2】:您可以执行以下操作。如果你想要IEnumerable<Plu>
,你可以从末尾删除.ToList()
。
dt.AsEnumerable().Select(x => new Plu
Id = x.Field<int>("ID_PLUREP"),
CodicePrep = x.Field<string>("CODICE_PRP"),
....
Attributes = attributi.AsEnumerable()
.Where(y => y.Field<int>("ID_PLUREP_VAT") == x.Field<int>("ID_PLUREP"))
.Select(z => new Attributi
....
).ToList(),
....
).ToList();
【讨论】:
以上是关于如何使用 LINQ 从 DataTable 中以 IEnumerable<MODEL> 形式获取数据?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用自己的 DataTable 类“Linq to DataTable”
使用 DataContext 从 LINQ 查询中填充 DataTable 的最快方法
从两个通过 LINQ 连接的 DataTable 创建组合的 DataTable。 C#