【问题标题】:C# treeview of SQL dataSQL 数据的 C# 树视图
【发布时间】:2013-11-05 14:41:45
【问题描述】:

我有一个如下所示的 SQL 表:

orderID       customerName        orderDate          valueTotal
================================================================
   1             JohnA            01/02/2013            100
   2             AmandaF          01/02/2013            140
   3             JohnA            05/03/2013             58
   4             FredM            05/03/2013            200

我想通过orderDatecustomerNametreeView 上订购此信息,具体取决于用户设置,因此如果按customerName 订购,它看起来像这样:

JohnA
    01/02/2013
    05/03/2013
AmandaF
    01/02/2013
FredM
     05/03/2013

如果按orderDate排序,则像这样:

01/02/2013
    JohnA
    AmandaF
05/03/2013
    JohnA
    FredM

实现这一目标的最佳方法是什么?

编辑: 我正在使用 Windows 窗体

【问题讨论】:

  • 如何检索数据?您使用 Entity Foundation 还是 ADO.Net?您的数据是如何存储在程序中的?
  • 通过查询以正确的顺序排序,那么当您可以对数据的结构做出假设时,应该很容易在代码中构建树。
  • @DavidS.,我认为与其说是排序,不如说是关于分组。至少这是我从问题中理解的。
  • 更多的是对排序进行分组,没错。我的看法是,按需加载每一层可能更有意义,并使 UI 响应更灵敏。这样我就不得不从数据库中做更多的选择,但选择会非常简单。即:选择唯一的 orderDate,然后当用户扩展日期时,我会执行 Select unique customerName where orderDate =
  • 这就是为什么我询问数据是如何在内部存储的。您可以将所有内容加载到一个数据库访问中,然后只需使用GroupBy() 扩展方法。之后您可以迭代结果并将组添加到您的子树中。

标签: c# sql winforms treeview


【解决方案1】:

如果您使用的是 ADO.Net,请对此进行测试:

Dictionary<string, List<string>> groups = new Dictionary<string, List<string>>();

//set these dynamic
string groupingFieldName = "customerName";
string targetFieldName = "orderDate";


SqlDataReader rdr = sqlCmd.ExecuteReader();
while (rdr.Read())
{
    if (!groups.ContainsKey(rdr[groupingFieldName].ToString()))
    {
         groups.Add(rdr[groupingFieldName].ToString(), new List<string>());
    }
    groups[rdr[groupingFieldName].ToString()].Add(rdr[targetFieldName].ToString());
}

//next, iterate the dictionary and populate the treeView
foreach (KeyValuePair<string, List<string>> group in groups)
{
     //add to treeView
}

请注意,这未经测试。您仍然需要对其进行测试。

【讨论】:

  • 我喜欢它背后的想法,但它假定我会同时加载所有的 treeView 节点,如果要加载的节点很多,可能需要很长时间才能处理。 .. 一次只加载一层不是更有意义吗?
  • 此外,从它假设只有两层的意义上说,它似乎不是很有可扩展性,虽然可以为更多层添加更多代码,但一旦开始,它似乎很快就会变得非常难以管理正在发生。
  • @cogumel0,我同意可扩展性部分。因此,我要求提供有关数据存储的更多详细信息。对于加载部分,这是值得商榷的。如果您确实有很多层,则多个数据请求可能(而且通常确实)需要比处理更长的时间。在这种情况下,本地缓存数据更有意义。
【解决方案2】:

我最终创建了两个函数来以更动态和可扩展的方式执行此操作。

    public static TreeNodeCollection SqlToTreeNodeHierarchy(this SqlDataReader dataReader, TreeNode parent)
    {
        // create a parent TreeNode if we don't have one, so we can anchor the new TreeNodes to it
        // I think this will work better than a list since we might be given a real parent..
        if (parent == null)
        {
            parent = new TreeNode("topNode");
        }

        while (dataReader.Read())
        {
            //at the beginning of each row, reset the parent
            var parentNode = parent;

            for (var i = 0; i < dataReader.FieldCount; i++)
            {
                // Adds a new TreeNode as a child of parentNode if it doesn't already exist
                // at this level, else it will return the existing TreeNode and save 
                // it onto parentNode. This way, subsequent TreeNodes will always be a child 
                // of this one, until a new row begins and the parent TreeNode is reset.
                parentNode = AddUniqueNode(dataReader[i].ToString(), parentNode);
            }
        }

        return parent.Nodes;
    }

    public static TreeNode AddUniqueNode(string text, TreeNode parentNode)
    {
        // if parentNode is null, create new treeNode and return it
        if (parentNode == null)
        {
            return new TreeNode {Name = text, Text = text};
        }

        // if parentNode is not null, do a find for child nodes at this level containing the key
        // we're after (text and name have the same value) and return the first one it finds
        foreach (var childNode in parentNode.Nodes.Find(text, false))
        {
            return childNode;
        }

        // Node does not yet exist, so just add a new node to the parentNode and return that
        return parentNode.Nodes.Add(text, text);
    }

那我只需要如下调用函数:

using (var sqlConn = new SqlConnection(connectionString))
{
    sqlConn.Open();

    const string query = "SELECT orderDate, customerName from MAIN";

    using (var sqlCommand = new SqlCommand(query, sqlConn))
    {
        using (var sqlDataReader = sqlCommand.ExecuteReader())
        {
            var treeNodeCollection = sqlDataReader.SqlToTreeNodeHierarchy(null);

            foreach (TreeNode treeNode in treeNodeCollection)
            {
                nativeTreeView.Nodes.Add(treeNode);
            }
        }
    }
}

通过这种方式,我可以根据需要使用任意数量的子节点进行扩展,并且它还为我提供了仅在展开时加载子节点的灵活性,方法是执行另一个 SQL 查询并将父节点作为刚刚展开的 TreeNode 传递.

【讨论】:

    猜你喜欢
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多