这是我们用于检索标题左连接到它的行(一个查询)的代码,而不是返回两个结果集(一个为头部,一个为行)从数据库中获取相关数据,我们总是得到一个头部,无论它有多少行。
你能帮我理解为什么如果底部的Distinct()被删除,它将返回与检索的行数相对应的HEAD副本吗?
-
这是因为在阅读器的每一行,我们项目一个头,即使它是相同的?所以如果HEAD有40条线,我们将同样的HEAD投射40次?那么一个DISTINCT将消除39,只返回1 ?
-
是否只是做。firstordefault()没有Distinct()在这种情况下等同于Distinct(),因为在一天结束时,它正在投射相同的HEAD对象?
public static IEnumerable<T> Select<T>(this IDataReader dr, Func<T> selector)
{
if (dr == null)
throw new ArgumentException(nameof(dr));
while (dr.Read())
yield return selector();
}
public void Test()
{
DTOHead head = null;
Dictionary<string, DTOHead> entryDictionary = new Dictionary<string, DTOHead>();
using (DbDataReader reader = cmd.ExecuteReader())
{
var head = reader.Select(dr =>
{
DTOHead entry = null;
if (!entryDictionary.TryGetValue((string)dr["Key"], out entry))
{
DTOHead dtoHead = new DTOHead();
dtoHead.Key = (string)dr["Key"]
dtoHead.Description = (string)dr["DESCRIPTION"];
dtoHead.Lines = new List<DTOLine>();
entry = dtoHead;
entryDictionary.Add(entry.Key, entry);
}
if (dr["LINE_NO"] != DBNull.Value)//skip, there are no lines for this one
{
DTOLine dtoLine = new DTOLine();
dtoLine.LineNo = (string)dr["LINE_NO"];
dtoLine.Qty = (string)dr["QTY"];
entry.Lines.Add(dtoLine);
}
return entry;
}).Distinct();
}
}
这是因为在读者的每一行,我们项目一个头,即使它是相同的?所以如果HEAD有40条线,我们将同样的HEAD投射40次?那么一个DISTINCT将消除39,只返回1 ?
是的,正是这样。您对Select
的实现将为reader
中的每一行投射一个DTOHead
。假设您在结果集中只有一个唯一的"Key"
,它将始终是相同的DTOHead
引用…您创建然后添加到entryDictionary
的一个。对Distinct
的调用然后删除所有重复项,并为您留下具有一个项目的IEnumerable<DTOHead>
。
是否只是做。firstordefault()没有Distinct()在这种情况下等同于Distinct(),因为在一天结束时,它正在投射相同的HEAD对象?
既然你指出你的结果集将只包含一个头,那么是的…你可以放弃对Distinct
的调用,只使用FirstOrDefault
,假设你不想要IEnumerable<DTOHead>
,只想要DTOHead
的实例。
如果是这种情况,你不需要entryDictionary
。您可以从reader
中读取第一行,然后使用Select
方法将其余行投影到IEnumerable<DTOLine>
中。
public void Test()
{
DTOHead head = null;
using (DbDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
// Deal with the first row by creating the DTOHead.
head = new DTOHead();
head.Key = (string)reader["Key"];
head.Description = (string)reader["DESCRIPTION"];
head.Lines = new List<DTOLine>();
if (reader["LINE_NO"] != DBNull.Value)//skip, there are no lines for this one
{
// Deal with the first row by creating the first DTOLine.
DTOLine line = new DTOLine();
line.LineNo = (string)reader["LINE_NO"];
line.Qty = (string)reader["QTY"];
head.Lines.Add(dtoLine);
// Project the remaining rows into lines.
head.Lines.AddRange(reader.Select(dr =>
{
DTOLine dtoLine = new DTOLine();
dtoLine.LineNo = (string)dr["LINE_NO"];
dtoLine.Qty = (string)dr["QTY"];
return dtoLine;
});
}
}
}
}