【问题标题】:help returning database rows using .net and SQL帮助使用 .net 和 SQL 返回数据库行
【发布时间】:2010-11-28 21:41:46
【问题描述】:

我正在尝试以这种格式返回数据库行 - 类别和子类别:

第 1 类
子类别
子类别
子类别

第 2 类
子类别
子类别
子类别

换句话说,返回类别及其下面的子类别。

我将类别和子类别存储在列表中,如果这是要走的路,我猜我的问题是我的 for 或 foreach 语法

这里是完整的代码:

 public class Categories
    {
        public string Name { get; set; }
        public string SubName { get; set; }
    }
    public void Category()
    {
        DataTable table = new DataTable();
        DataTable subTable = new DataTable();
        List<Categories> category = new List<Categories>();
        using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["localConnectionString"].ConnectionString))
        {
            using (SqlCommand comm = new SqlCommand())
            {
                comm.Connection = conn;
                comm.CommandType = CommandType.StoredProcedure;
                comm.CommandText = "Category_Admin_GetAll";
                conn.Open();
                SqlDataReader reader = comm.ExecuteReader();
                table.Load(reader);
                reader.Close();
                conn.Close();
            }
            using(SqlCommand comm = new SqlCommand())
            {
                comm.Connection=conn;
                comm.CommandType= CommandType.StoredProcedure;
                comm.CommandText = "SubCategory_Admin_GetAll";
                conn.Open();
                SqlDataReader reader = comm.ExecuteReader();
                subTable.Load(reader);
                reader.Close();
                conn.Close();
            }
        }
        foreach (DataRow dRow in table.Rows)
        {
            category.Add(new Categories { Name = dRow["Name"].ToString() });
        }
        foreach (DataRow dRow in subTable.Rows)
        {
            category.Add(new Categories { SubName = dRow["SubCategoryName"].ToString() });
        }
        int t = category.Count;
        resultSpan.InnerHtml += "<table class='table_category'>";
        resultSpan.InnerHtml += "<tr><td>ACTIVE</td><td>NAME</td></tr>";
        resultSpan.InnerHtml +="<tr><td></td><td>"+ category[0].Name+"</td></tr>";
            for (int i = 0; i < t; i++)
            {
                resultSpan.InnerHtml += "<tr><td></td><td>" + category[i].SubName + "</td></tr>";
            }
        resultSpan.InnerHtml += "</table>";
    }

【问题讨论】:

  • 嗯,你的问题是什么?您的代码有问题需要帮助吗?
  • 哦,孩子,你有一大堆问题。首先创建一个带有CategoryId, SubCategoryId, Name 的SubCategryClass,然后将Categories 类更改为CategoryId, Name。如果你从那里开始,其余的就会很自然地进行。
  • 你的类别和子类别是如何联系起来的,即子类别表中的外键叫什么?
  • @Heinzi,我的 subCategory 表有一个名为 CategoryID 的列,它链接到 Category 表上的 CategoryID。

标签: c# asp.net ado.net


【解决方案1】:

首先,遍历所有类别。然后,在该循环中,遍历属于该类别的所有子类别。这里,我将数据直接输出为 HTML;如果你想这样做,你也可以填充一个列表。

resultSpan.InnerHtml += "<table class='table_category'>";
resultSpan.InnerHtml += "<tr><td>ACTIVE</td><td>NAME</td></tr>";

foreach (DataRow dRow in table.Rows)
{
    // category
    resultSpan.InnerHtml +="<tr><td></td><td>"+ dRow.Field<string>("Name") +"</td></tr>";

    var id = dRow.Field<int>("CategoryID");
    var subcategories = from row in subTable.AsEnumerable()
                        where row.Field<int>("CategoryID") = id
                        select row.Field<string>("SubCategoryName");

    foreach (string subcategory in subcategories) {
         // subcategory
         resultSpan.InnerHtml += "<tr><td></td><td>" + subcategory + "</td></tr>";
    }
}

resultSpan.InnerHtml += "</table>";

当然,如果您可以将CategoryName 加入您的subTable 存储过程,那么一切都会变得容易得多(并且您不再需要table)。一定要ORDER BY CategoryName,这样同类别的子类别就“分组在一起”了,那么就可以这样使用代码:

resultSpan.InnerHtml += "<table class='table_category'>";
resultSpan.InnerHtml += "<tr><td>ACTIVE</td><td>NAME</td></tr>";

string lastCategory = null;

foreach (DataRow dRow in subTable.Rows)
{
    // category, if new one
    var category = dRow.Field<string>("CategoryName");
    if (category != lastCategory) {
        lastCategory = category;
        resultSpan.InnerHtml +="<tr><td></td><td>"+ category +"</td></tr>";
    }

    // subcategory
    resultSpan.InnerHtml += "<tr><td></td><td>" + dRow.Field<string>("SubCategoryName") + "</td></tr>";
}

resultSpan.InnerHtml += "</table>";

【讨论】:

  • Heinzi,这有效,只是它根据显示的子类别多次返回相同的类别。例如。如果显示 5 个子类别,则显示类别 1(项目 1-5)5 次(实例)。我的存储过程使用的是内连接,而不是每个表都存储在单独的数据表中。
  • @nick: 你的存储过程Category_Admin_GetAll 是否有可能不小心返回了 Category1 五次而不是一次?事实上,如果你已经使用了带有内部连接的存储过程,那么在子类别SP中将类别名称连接到子类别并使用one数据表不是更容易吗?
【解决方案2】:

直接使用 ado.net 比其他方法更复杂,效率更低。

MS 已经为数据访问引入了实体框架,您的数据访问代码可以简化为这样的:

var CategoryQuery = from d in context.Category.Include("SubCategory")
                  select d;

见:http://msdn.microsoft.com/en-us/data/ef.aspx

【讨论】:

    【解决方案3】:

    你让你的生活变得更加艰难。

    我推荐两件事:

    1) 照@Shiraz 所说的去做 - 使用实体框架

    2) 如果这不可能,为什么不使用单个存储过程,它基本上执行 UNION 或 JOIN(不完全确定您的架构/逻辑)。

    您为合并/拼接类别所做的代码是数据库问题,您不应该在代码中这样做。

    【讨论】:

      【解决方案4】:

      1.- 如果(仅当所有类别包括所有子类别)按类别名称对它们进行排序时,创建一个使两个表交叉连接的存储过程 2.- 将您的类别对象更改为具有类别子集,以便您可以将子类别添加到您的类别对象中

      IEnumerable<DataRow> rows = dt.Rows.AsEnumerable();
      
      var categories = rows.Select(dr=>dr["fieldname"].ToString()).Distinct().Select(name=> new Category(){Name=name});
      var subcategories rows.Select(dr=> new Category(){ SubName =dr["subname"]});
      categories.ForEach(c=>c.SubcCategories = subcategories); 
      

      【讨论】:

      • 使用 LINQ 会更容易吗?
      【解决方案5】:

      用于调用存储过程的 C# 代码返回一个排序的数据列表,填充一个数据表并循环它,非常简单。

      C#代码

      const string DB_CONN_STR = "Server=127.0.0.1;Uid=foo_dbo;Pwd=pass;Database=foo_db;";
      
      MySqlConnection cn = new MySqlConnection(DB_CONN_STR);
      
      MySqlDataAdapter adr = new MySqlDataAdapter("category_hierarchy", cn);
      
      adr.SelectCommand.CommandType = CommandType.StoredProcedure;
      DataTable dt = new DataTable();
      adr.Fill(dt); //opens and closes the DB connection automatically !!
      
      foreach(DataRow dr in dt.Rows){
          Console.WriteLine(string.Format("{0} {1}", 
              dr.Field<uint>("cat_id").ToString(), dr.Field<string>("cat_name").ToString()));
      }
      
      cn.Dispose();
      

      使用 DataTable 的明显好处是:轻量级、可序列化、断开连接 - 所有这些都允许应用程序具有高性能和可扩展性。但是,如果您需要这样做,没有什么能阻止您循环数据表并填充您自己的集合!

      问题中最难的部分是编写一个存储过程,该过程按您需要的顺序返回数据。就我个人而言,我会使用邻接表方法以及存储过程和公用表表达式 (CTE) 来实现类别层次结构。这种方法的优点是类别层次结构可以是多级的,编码简单,比嵌套集等其他方法更容易管理和维护。

      有关 CTE 的更多信息 - 请参阅 http://msdn.microsoft.com/en-us/library/ms190766.aspx

      不幸的是,我现在手头只有一个 MySQL 实现,这有点冗长,因为 MySQL 缺乏使这项任务在 RDBMS 中变得微不足道的功能,例如 SQL Server (CTE) 和 Oracle(连接方式)。但是,网络上有大量资源将向您展示如何使用 CTE 和存储过程来完成您需要的工作。如果您对我如何在 MySQL 中实现这一点感兴趣,我在此答案的底部提供了指向完整源代码的链接。

      无论您使用什么 RDBMS,存储过程的结果应该如下所示:

      call category_hierarchy();
      
      cat_id  cat_name    parent_cat_id   parent_cat_name depth
      ======  ========    =============   =============== =====
      2        Cat 1          1            Categories        1
      3        Cat 1-1        2            Cat 1             2
      4        Cat 1-2        2            Cat 1             2
      5        Cat 1-2-1      4            Cat 1-2           3
      7        Cat 2          1            Categories        1
      8        Cat 2-1        7            Cat 2             2
      9        Cat 2-2        7            Cat 2             2
      10      Cat 2-2-1      9            Cat 2-2           3
      

      我的答案的完整源代码可以在这里找到:http://pastie.org/1331218

      希望这能引起人们的兴趣:)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-11-01
        • 1970-01-01
        • 2010-11-11
        • 1970-01-01
        • 2010-11-30
        • 2020-02-01
        • 2011-08-01
        相关资源
        最近更新 更多