[ASP.net] GridView、ListView資料列的上移下移(底層sort資料異動的演算法)
要實現這個功能,我見過有使用Container.DataItemIndex、抓GridView該列的列索引或使用Row_Number()處理等等。
這邊紀錄一下我見過程式碼最少的演算法(看來看去還是靠SQL做最快)
需求:因為客戶想要在後台維護資料「上移下移」時候,前台網站的資料排序跟著後台資料排序異動
所以
1. 先把資料表加一個sort欄位
2. 若該資料表為階層式資料(如員工資料表),則同一層的sort數字不能重覆
以上面那張圖來看,因為北風資料庫的Categories資料表只有一層
所以該sort欄位數字全部不重覆,否則在上移下移過程中,會發現資料沒有移動。
3. C# Server端只要得知 點選該列的sort數字,就可以進行資料排序的移動。
請先看SQL語法撈出全部的資料:
現在假設ListView點選第三筆資料要下移,為了要和第4筆交換sort數字,所以Select 語法:
若ListView點選第四筆資料要上移,為了要和第3筆交換sort數字,Select語法:
SQL語法準備好後,開工寫程式
.aspx
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
</head>
<body>
<form id="form1" runat="server">
<asp:SqlDataSource runat="server" ID="sds_Categories" ConnectionString="<%$ ConnectionStrings:Conn_E %>"
SelectCommand="SELECT [CategoryID], [CategoryName], [Description], [sort] FROM [Categories]
Order by sort ASC" />
<asp:ListView ID="lv_Categories" runat="server" DataKeyNames="CategoryID"
DataSourceID="sds_Categories" onitemcommand="lv_Categories_ItemCommand">
<ItemTemplate>
<tr >
<td>
<asp:Label ID="CategoryIDLabel" runat="server" Text='<%# Eval("CategoryID") %>' />
</td>
<td>
<asp:Label ID="CategoryNameLabel" runat="server" Text='<%# Eval("CategoryName") %>' />
</td>
<td>
<asp:Label ID="DescriptionLabel" runat="server" Text='<%# Eval("Description") %>' />
</td>
<td>
<asp:Label ID="sortLabel" runat="server" Text='<%# Eval("sort") %>' />
</td>
<td>
<asp:Button ID="cmd_Down" Text="下移" runat="server" CommandName="ChangeSort" CommandArgument='<%# Eval("sort") %>' ToolTip="Down" />
<asp:Button ID="cmd_Up" Text="上移" runat="server" CommandName="ChangeSort" CommandArgument='<%# Eval("sort") %>' ToolTip="Up" />
</td>
</tr>
</ItemTemplate>
<LayoutTemplate>
<table id="itemPlaceholderContainer" runat="server" border="1" >
<tr >
<th>
CategoryID
</th>
<th>
CategoryName
</th>
<th>
Description
</th>
<th>
sort
</th>
<th>
異動
</th>
</tr>
<tr id="itemPlaceholder" runat="server">
</tr>
</table>
</LayoutTemplate>
</asp:ListView>
</form>
</body>
</html>
.cs 檔
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Configuration;
using System.Data;
using System.Data.SqlClient;
public partial class _Default : System.Web.UI.Page
{
protected void lv_Categories_ItemCommand(object sender, ListViewCommandEventArgs e)
{
if (e.CommandName=="ChangeSort")
{
string sort = e.CommandArgument.ToString();//點選該列的sort數字
string DownUp = ((Button)e.CommandSource).ToolTip;//下移或上移的Command
#region 取得要交換sort的兩筆資料
string sql = " SELECT Top 2 [CategoryID],[sort] "+
" FROM [Categories]"+
" Where sort" + ((DownUp=="Down")? ">=":"<=") + sort +
" Order by sort " + ((DownUp == "Down") ? "ASC" : "DESC");
//以上是呈現端Order by sort ASC的語法
//若呈現端Order by sort DESC的話,條件要顛倒
DataTable dt = this.queryDataTable(sql);
#endregion
if (dt.Rows.Count >= 2)//防呆第一列上移動作和最後一列下移動作
{
string firstID = dt.Rows[0]["CategoryID"].ToString();
string firstSort = dt.Rows[0]["sort"].ToString();
string secondID = dt.Rows[1]["CategoryID"].ToString();
string secondSort = dt.Rows[1]["sort"].ToString();
this.ExecuteNonQuery(@"SET XACT_ABORT ON
Begin Transaction
Update Categories Set sort='" + secondSort + "' Where CategoryID = '" + firstID + @"' /*將第一筆sort換成第二筆*/
Update Categories Set sort='" + firstSort + "' Where CategoryID = '" + secondID + @"' /*將第二筆sort換成第一筆*/
Commit Transaction");
}
}
lv_Categories.DataBind();//重新資料繫結
}
protected string Conn_E = WebConfigurationManager.ConnectionStrings["Conn_E"].ConnectionString;
protected DataTable queryDataTable(string sql)
{
using (SqlConnection conn = new SqlConnection(this.Conn_E))
{
SqlDataAdapter da = new SqlDataAdapter(sql, conn);
DataSet ds = new DataSet();
da.Fill(ds);
return (ds.Tables.Count > 0) ? ds.Tables[0] : new DataTable();
}
}
protected int ExecuteNonQuery(string sql)
{
using (SqlConnection conn = new SqlConnection(this.Conn_E))
{
SqlCommand cmd = new SqlCommand(sql, conn);
int rows = 0;
conn.Open();
rows = cmd.ExecuteNonQuery();
return rows;
}
}
}
2011.7.2 追記
如果此Table有做使用者維護畫面,而且有新增語法的話,該SQL語法最好用Begin Transaction - Commit Transaction包住
並在之前插入語法
SET TRANSACTION ISOLATION LEVEL
SERIALIZABLE;
參考MSDN論壇