使用嵌套转发器对第一组DataSet进行分组

时间:2014-10-02 15:26:31

标签: c# asp.net webforms

假设我有一些像这样的书籍数据:

enter image description here

我有一个像SELECT * FROM BookData这样的查询,它以上述格式输出。

我想使用嵌套的转发器控件来输出html <table>中的数据,看起来像这样,数据结果按作者分组:

enter image description here

到目前为止,我的asp.net Web表单代码如下所示:

<table>
    <asp:Repeater ID="RepeaterInner" runat="server">
    <ItemTemplate>
    <tr>
        <td><asp:TextBox Text='<%# Eval("Book") %>' /></td>
        <td><asp:TextBox Text='<%# Eval("Author") %>' /></td>
        <td><asp:TextBox Text='<%# Eval("PublishDate") %>' /></td> 
        <td><asp:TextBox Text='<%# Eval("Pages") %>' /></td>         
    </tr>
    </ItemTemplate>
    </asp:Repeater>
</table>

和我背后的代码:

protected void Page_Load(object sender, EventArgs e)
        {          

            DataSet ds = GetData();
            RepeaterInner.DataSource = ds;
            RepeaterInner.DataBind();

        }

        private DataSet GetData() 
        {
            string CS = ConfigurationManager.ConnectionStrings["MyDB"].ConnectionString;
            using (SqlConnection con = new SqlConnection(CS))
            {
                using (SqlCommand cmd = new SqlCommand("spGetData"))
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.Connection = con;
                    con.Open();
                    SqlDataAdapter da = new SqlDataAdapter();
                    da.SelectCommand = cmd;
                    DataSet ds = new DataSet();
                    da.Fill(ds);
                    con.Close();
                    return ds;                   
                }
            }
        }

对于最终产品,我希望它看起来像这样:

<table>
    <asp:Repeater ID="RepeaterOuter" runat="server">
    <ItemTemplate>
        <tr>
        <td><asp:TextBox Text='<%# Eval("Author") %>' /></td>
        </tr>
        <asp:Repeater ID="RepeaterInner" runat="server">
        <ItemTemplate>
        <tr>
            <td><asp:TextBox Text='<%# Eval("Book") %>' /></td>
            <td><asp:TextBox Text='<%# Eval("PublishDate") %>' /></td> 
            <td><asp:TextBox Text='<%# Eval("Pages") %>' /></td>         
        </tr>
        </ItemTemplate>
        </asp:Repeater>    
    </ItemTemplate>
    </asp:Repeater>
</table>

但我真的很困惑如何做才能使上述事情发生。可以使用我的一个存储过程生成的DataSet上面的一个来完成吗?如果有的话,我需要为每个Repeater的ItemDataBound事件处理程序做什么?

谢谢。

3 个答案:

答案 0 :(得分:2)

您可以使用GroupBy按作者对数据进行分组,然后您只需将内部转发器绑定到书籍组:

RepeaterOuter.DataSource = data.GroupBy(book => book.Author, (Author, Books) => new
{
    Author,
    Books,   
});

现在您已将数据转换为正确的格式,您只需要将书籍的collectino绑定到标记中的内部转发器:

<asp:Repeater ID="RepeaterInner" runat="server" DataSource='<%# Eval("Books") %>'>

答案 1 :(得分:2)

您的存储过程看起来只返回一个数据表。所以GetData方法应该返回DataTable而不是DataSet

private DataTable GetData()
{
    DataTable dt = new DataTable();
    using (SqlConnection c = new SqlConnection(ConfigurationManager.ConnectionStrings["MyDB"].ConnectionString))
    {
        c.Open();
        using (SqlCommand cmd = new SqlCommand("spGetData", c))
        {
            cmd.CommandType = CommandType.StoredProcedure;
            using (SqlDataAdapter da = new SqlDataAdapter(cmd))
            {
                da.Fill(dt);
            }
        }
    }
    return dt;
}

Servy的解决方案帮助我更好地理解IGrouping。更多地建立他的想法: 您的Page_Load方法:

protected void Page_Load(object sender, EventArgs e)
{
    DataTable dataTbl = this.GetData();

    //Cast the Rows collection so we can use LINQ
    IEnumerable<dynamic> data = dt.Rows.Cast<DataRow>()

        // Group the DataRows by the column ["Author"]
        .GroupBy<DataRow, String>(d => Convert.ToString(d["Author"]))

        // GroupBy returns an IEnumerable<IGrouping<TKey, TSource>>
        // in this case we have a String (Authors Name) and 
        // DataRows with the book information. From these IGroupings
        // we want to return a dynamic class that has properties:
        //  - Author (string it is the .Key in the IGrouping) 
        //  - Books (Collection of another dynamic class that has Book properties)
        .Select<IGrouping<String, DataRow>, dynamic>(grp => {
            return new {
                Author = grp.Key,
                // grp right now is a collection of DataRows
                // make each row into a dynamic class that has
                // book properties so that Eval("PropName")
                // plays nice
                Books = grp.Select<DataRow, dynamic>(row => {
                    return new {
                        Book = Convert.ToString(row["Book"]),
                        PublishDate = Convert.ToString(row["PublishDate"]),
                        Pages = Convert.ToString(row["Pages"])
                    };
                })
            };
        });

    RepeaterOuter.DataSource = data;
    RepeaterOuter.DataBind();
}

页码:

<table>
    <asp:Repeater ID="RepeaterOuter" runat="server">
        <ItemTemplate>
            <tr>
                <td><asp:TextBox runat="server" Text='<%# Eval("Author") %>' /></td>
            </tr>
            <asp:Repeater ID="RepeaterInner" runat="server" DataSource='<%# Eval("Books") %>'>
                <ItemTemplate>
                <tr>
                   <td><asp:TextBox runat="server" Text='<%# Eval("Book") %>' /></td>
                   <td><asp:TextBox runat="server" Text='<%# Eval("PublishDate") %>' /></td> 
                   <td><asp:TextBox runat="server" Text='<%# Eval("Pages") %>' /></td>
                </tr>
                </ItemTemplate>
            </asp:Repeater>    
        </ItemTemplate>
    </asp:Repeater>
</table>

答案 2 :(得分:0)

针对cmd.prompt解决方案的更简化的lambda表达式:

    DataTable data = GetData();

    var groupedData = data.AsEnumerable()
        .GroupBy(d => new
        {
            Author = d["Author"]
        })
        .Select(grp => new
        {
            grp.Key,
            Books = grp.Select(row => new
            {
                Book = row["ID"],
                PublishDate = row["Name"],
                Pages = row["Pages"]
            })
        });

    RepeaterOuter.DataSource = groupedData;
    RepeaterOuter.DataBind();