假设我有一些像这样的书籍数据:
我有一个像SELECT * FROM BookData
这样的查询,它以上述格式输出。
我想使用嵌套的转发器控件来输出html <table>
中的数据,看起来像这样,数据结果按作者分组:
到目前为止,我的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
事件处理程序做什么?
谢谢。
答案 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();