我有一个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>
。。。
问题是,DataTable只知道单元格中有哪些值。它不知道这些价值观代表什么。它不知道0列中的数字实际上是Id。它不知道1列中的字符串是客户的名称,而2列中的DateTime是客户的生日。
如果将来要将此数据表(或类似数据表(的内容用于其他查询,则需要将DataRow转换为它们所代表的项。
一旦您获得了从DataRow到Plu的转换,您就可以将DataTable转换为IEnumerable<Plu>
,并对其进行其他LINQ处理。
用法如下:
DataTable table = ...
var mySelectedData = table.AsEnumerable().ToPlus()
.Where(plu => ...)
.Select(plu => new {...})
.ToList();
您需要两个扩展方法:一个将DataRow转换为Plu,另一个将数据行序列转换为Plus序列。参见扩展方法解密
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的顺序思考。
您可以执行以下操作。如果您想要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();