Parent/Child 数据库数据绑定到 class 的 C# 列表

C# List of Parent/Child DB data bind to class

这是我们的代码,用于检索 header 左连接到它的行(一个查询),而不是 returning 两个结果集(一个用于头部,一个用于行)以获取来自数据库的相关数据,我们总是得到一个头,不管它有多少行。

你能帮我理解为什么如果删除底部的 Distinct() ,它会 return HEAD 重复对应于检索到的行数。

  1. 这是因为对于 reader 中的每一行,我们投影一个 HEAD,即使它是相同的?所以如果 HEAD 有 40 行,我们要投影同一个 HEAD 40 次?那么 DISTINCT 将消除 39 而 return 只消除一个?

  2. 在这种情况下,不使用 Distinct() 执行 .FirstOrDefault() 是否等同于 Distinct(),因为在一天结束时,它会投射相同的 HEAD object?

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();
    }
}

Is this because for every row in the reader, we project a HEAD even if it's the same? so if the HEAD has 40 lines, we are projecting the same HEAD 40 times? then a DISTINCT will eliminate 39 and return just one?

没错,就是这个。 Select 的实施将为 reader 中的每一行投射一个 DTOHead。假设您的结果集中只有一个唯一的 "Key",它将始终是相同的 DTOHead 引用...您创建的那个然后添加到 entryDictionary。然后调用 Distinct 删除所有重复项,并为您留下一个 IEnumerable<DTOHead> 和一个项目。

Would just doing .FirstOrDefault() without Distinct() be equivalent in this scenario as Distinct() because at the end of the day, it is projecting the same HEAD object?

既然你指出你的结果集将只包含一个头,那么是的......你可以放弃对 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;
                });
            }
        }
    }
}