简体   繁体   English

使用.net和SQL帮助返回数据库行

[英]help returning database rows using .net and SQL

I'm trying to return database rows - category and sub category in this format: 我正在尝试以这种格式返回数据库行-类别和子类别:

Category 1 第1类
SubCategory 子类别
SubCategory 子类别
SubCategory 子类别

Category 2 2类
SubCategory 子类别
SubCategory 子类别
SubCategory 子类别

In other words return the category with the sub categories that belong to it underneath. 换句话说,返回类别及其下面的子类别。

I am storing the category and sub category in a List, if this is the way to go, I'm guessing my problem is my for or foreach syntax 我将类别和子类别存储在列表中,如果这是一种方法,我猜我的问题是我的for或foreach语法

Here is the full code: 这是完整的代码:

 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>";
    }

First, loop through all categories. 首先,遍历所有类别。 Then, within that loop, loop through all subcategories beloging to that category. 然后,在该循环中,遍历所有要登录到该类别的子类别。 Here, I output the data directly into HTML; 在这里,我将数据直接输出到HTML中。 you can also populate a list instead, if you want to do that. 如果您愿意,也可以填充列表。

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>";

Of course, if you can just join the CategoryName to your subTable stored procedure, everything gets much easier (and you don't need table anymore). 当然,如果您可以仅将CategoryName加入到subTable存储过程中,一切将变得更加容易(并且您不再需要table )。 Be sure to ORDER BY CategoryName , so that subcategories with the same category are "grouped together", then you can use code like this: 确保使用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>";

Using ado.net directly is more complicated and less productive than other methods. 与其他方法相比,直接使用ado.net更为复杂且效率较低。

MS has introduced Entity Framework for data access, your data access code could be reduced to something like this: MS引入了用于数据访问的实体框架,您的数据访问代码可以简化为以下形式:

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

see: http://msdn.microsoft.com/en-us/data/ef.aspx 请参阅: http//msdn.microsoft.com/en-us/data/ef.aspx

Your making your life more difficult than it has to be. 您使自己的生活变得更加艰难。

I'd recommend two things: 我建议两件事:

1) Do what @Shiraz says - use Entity Framework 1)做@Shiraz说的-使用实体框架

2) If that's not possible, why not use a single stored procedure , that basically performs a UNION or JOIN (not entirely sure about your schema/logic). 2)如果不可能,为什么不使用单个存储过程 ,该存储过程基本上执行UNION或JOIN(不完全确定模式/逻辑)。

The code your doing to marry up/stitch the categories is a database concern, you shouldn't be doing it in the code. 嫁接/缝合类别的代码是数据库方面的问题,您不应该在代码中进行。

1.- make a single store procedure that brings both tables cross joined if(only if all categories include all subcategories) order them by category name 2.- change your category object to have a subset of categories so you can add the subcategories into your category object 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); 

The C# code for calling a stored procedure which returns a sorted list of data, populates a datatable and loops it, is simple in the extreme. 在极端情况下,用于调用存储过程的C#代码将返回一个排序的数据列表,填充一个数据表并对其进行循环。

C# code 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();

The obvious benefits of using a DataTable are that it is: lightweight, serialisable, disconnected - all things that allow applications to be performant and to scale. 使用DataTable的明显好处是:轻巧,可序列化,断开连接-所有使应用程序能够高效运行和扩展的事物。 However, there's nothing stopping you looping the datatable and populating your own collection if that's what you need to do ! 但是,如果您要做的是,没有什么可以阻止您循环数据表并填充自己的集合!

The hardest part of problem is coding a single stored procedure that returns the data in the order that you require it. 问题中最难的部分是对单个存储过程进行编码,该存储过程将按所需顺序返回数据。 Personally I would implement a category hierarchy using the adjacency list method in conjunction with a stored procedure and common table expressions (CTE). 我个人将使用邻接表方法结合存储过程和公用表表达式(CTE)来实现类别层次结构。 The advantages of this approach are that the category hierarchy can be multi-level, it's simple to code and it's much easier to manage and maintain than other methods such as nested sets. 这种方法的优点是类别层次结构可以是多层的,它很容易编码,并且比嵌套集等其他方法更易于管理和维护。

More info on CTE - see http://msdn.microsoft.com/en-us/library/ms190766.aspx 有关CTE的详细信息-请参阅http://msdn.microsoft.com/zh-cn/library/ms190766.aspx

Unfortunately I only have a MySQL implementation to hand right now which is a little long winded as MySQL lacks the features that makes this task trivial in RDBMS such as SQL Server (CTE) and Oracle (connect by). 不幸的是,由于MySQL缺乏使RDBMS中的这项任务变得微不足道的功能,例如SQL Server(CTE)和Oracle(connect by),因此我现在只有一个MySQL实现,这有点麻烦了。 However, there are plenty of resources on the web that will show you how to use CTE and stored procedures to do what you need. 但是,网络上有大量资源,将向您展示如何使用CTE和存储过程来完成所需的工作。 If you're interested in how I've implemented this in MySQL I've included a link to the full source at the bottom of this answer. 如果您对我如何在MySQL中实现此方法感兴趣,则在此答案的底部提供了指向完整源代码的链接。

Whatever RDBMS you use the results of the stored procedure should be something like as follows: 无论使用哪种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

Full source code for my answer can be found here : http://pastie.org/1331218 我的答案的完整源代码可以在这里找到: http : //pastie.org/1331218

Hope this proves of interest :) 希望这证明有兴趣:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM