【ASP.NET】利用Repeater完成对SQL Server数据库的增删改查

在ASP.NET对于SQL Server数据库的增删改查自然是便利的,ASP.NET提供了大量封装好的数据库表格,例如GridView什么的,但这些组件只能通过VS自带的属性进行样式的修改,远不如类似与其它语言的循环结构foreach的Repeater,能够自己在“源”代码中的修改遍历,当然这个组件并不是这么好驾驭是真的。

下面有一个例子说明这个组件的运用。

在数据库test中有一张用烂的user_info表,结构如下:


建表语句如下:

CREATE TABLE [dbo].[user_info](
	[id] [int] IDENTITY(1,1) NOT NULL,
	[username] [varchar](50) NULL,
	[password] [varchar](50) NULL,
PRIMARY KEY CLUSTERED 
(
	[id] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
在Default.aspx页面,完成对这个表的增删改查操作。

要求不能出现相同的用户名。


解决方案的目录结构如下所示:


其中DB.cs是《【C#】利用C#窗体与SQL Server的连接、Treeview制作SQL Server数据库查看器》(点击打开链接)中介绍过的数据库查询类,窗体程序与ASP.NET是通用的,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;//DataTable用到
using System.Data.SqlClient;//一系列的数据库操作类用到
using System.Configuration;

namespace Repater
{
    class DB : IDisposable
    {
        private SqlConnection sqlConnection;

        // 以下代码,保证该类只能有一个实例        

        // 在自己内部定义自己的一个实例,只供内部调用  
        private static DB db = null;

        // 这个类必须自动向整个系统提供这个实例对象  
        // 这里提供了一个供外部访问本class的静态方法,可以直接访问  
        public static DB getInstance()
        {
            if (db == null)
            {
                db = new DB();
            }
            return db;
        }

        private DB()// 私有无参构造函数
        {
            sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["myCon"].ToString());
            sqlConnection.Open();
        }

        //单例化结束

        public DataTable getBySql(string sql, Object[] param)
        {//查询
            sql = String.Format(sql, param);//用字符串参数替换的形式防止注入
            SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(new SqlCommand(sql, sqlConnection));
            DataTable dataTable = new DataTable();
            sqlDataAdapter.Fill(dataTable);
            return dataTable;
        }
        public DataTable getBySql(string sql)
        {//无参数的查询
            SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(new SqlCommand(sql, sqlConnection));
            DataTable dataTable = new DataTable();
            sqlDataAdapter.Fill(dataTable);
            return dataTable;
        }

        public void setBySql(string sql, Object[] param)
        { //无查询结果的修改
            sql = String.Format(sql, param);//用字符串参数替换的形式防止注入            
            new SqlCommand(sql, sqlConnection).ExecuteNonQuery();
        }
        public void setBySql(string sql)
        { //无参数,无查询结果的修改
            new SqlCommand(sql, sqlConnection).ExecuteNonQuery();
        }

        public void Dispose()
        {//相当于析构函数
            sqlConnection.Close();
            //在C#中关闭数据库连接不能在类的析构函数中关,否则会抛“内部 .Net Framework 数据提供程序错误 1”的异常
            //通过实现C#中IDisposable接口中的Dispose()方法主要用途是释放非托管资源。
        }
    }
}

唯一的不同,是这个数据库连接字符串与《【ASP.NET】将数据库连接字符串写在Web.config》( 点击打开链接)同样在Web.Config中配置过,再调用:

  <connectionStrings>
    <add name="myCon"
         connectionString="server=.\SQLEXPRESS;database=test;Trusted_Connection=SSPI;"
         providerName="using System.Data.SqlClient;"/>
  </connectionStrings>

在Defalut.aspx的界面布置如下,双击Repeater添加一个OnItemCommand="Repeater1_ItemCommand"事件这一点很关键,是整个工程的灵魂。同时双击下方的“添加”按钮,添加一个button,onclick事件。


之后,先不急着在Default.aspx.cs中编程,先修改源视图中的代码,也就是Default.aspx,具体如下:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Repater._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Repeater ID="Repeater1" runat="server" OnItemCommand="Repeater1_ItemCommand">
            <HeaderTemplate><%--不参与循环的头部--%>
                <table border="1">
                    <tr>
                        <th>
                            用户名
                        </th>
                        <th>
                            密码
                        </th>
                        <th>
                            操作
                        </th>
                    </tr>
            </HeaderTemplate><%--循环产生的部分,被绑定的数据也就是DataTable有多少行,这里就会循环多少次--%>
            <ItemTemplate>
                <tr>
                    <td><%--输出数据,利用到<%#Eval("username")%>,里面的任何一个符号,主要是双引号是不能改变的--%>
                        <asp:TextBox ID="TextBox1" runat="server" Text='<%#Eval("username")%>' />
                    </td><%--因此如果出现如上的引号嵌套,仅能将外面的引号改成单引号--%>
                    <td>
                        <asp:TextBox ID="TextBox2" runat="server" Text='<%#Eval("password")%>' />
                    </td>
                    <td><%--这里,CommandName,CommandArgument都是传给OnItemCommand="Repeater1_ItemCommand"的参数--%>
                        <asp:Button runat="server" CommandName="update" CommandArgument='<%#Eval("id")+","+(Container as RepeaterItem).ItemIndex%>'
                            Text="修改" /><%--修改按钮比较复杂,除了在CommandName传递一个update给后台,标识自己是修改,还要同时传递两个参数一个打印的id,与该行的行数用于发现TextBox--%>
                        <asp:Button runat="server" CommandName="del" CommandArgument='<%#Eval("id")%>' Text="删除"
                            OnClientClick='return confirm("确定此操作吗?")' />
                    </td>
                </tr>
            </ItemTemplate>
            <FooterTemplate><%--不参与循环的尾部--%>
                </table>
            </FooterTemplate>
        </asp:Repeater>
        <b>插入用户:</b><br /><%--这里没啥好说的,就一个asp.net中常见的表单--%>
        用户名:<asp:TextBox ID="TextBox1" runat="server" />密码:<asp:TextBox ID="TextBox2" runat="server" />
        <asp:Button runat="server" ID="Button1" Text="添加" OnClick="Button1_Click" />
    </div>
    </form>
</body>
</html>

具体见相应的注释,这里,其实主要的难点就出现在,输出绑定数据的引号的问题,它<%#Eval("DataTable的字段(列)名")%>一定要双引号,非常奇怪,出现引号嵌套,你还不能用《【JavaScript】引号嵌套问题与Javascript中多行HTML写作方案》( 点击打开链接)那套规则来搞,它一定要双引号,外面值能改成单引号咯,否则会出现如下的错误:


同时,如果你要输出绑定数据的同时,同时带上其它数据的输出,那你仅能类似这种形式搞了:CommandArgument='<%#Eval("id")+","+(Container as RepeaterItem).ItemIndex%>'这也没办法,ASP.NET是这样规定的。

也可以看到Repeater的代码类似其它语言的foreach,你可以自由地修改里面的输出形式,可以是table,可以是div等等

之后在后端Default.aspx.cs你就这样写,配合Default.aspx完成SQL Server数据库的增删改查:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Repater
{
    public partial class _Default : System.Web.UI.Page
    {
        DB db;
        protected void Page_Load(object sender, EventArgs e)
        {
            db = DB.getInstance();//必须放在!Page.IsPostBack外面,因为每次离开~加载这个页面,伴随这数据库实例被销毁,你必须将其重新初始化
            if (!Page.IsPostBack)//必须有,规定数据不能多次被绑定。
            {
                Repeater1.DataSource = db.getBySql("select * from [user_info]");
                Repeater1.DataBind();//直接通过绑定来完成Repeater的输出
            }
        }

        protected void Repeater1_ItemCommand(object source, RepeaterCommandEventArgs e)
        {
            if (e.CommandName == "update")//如果点击的是被标记为CommandName="update"的按钮,也就是修改按钮
            {
                int id = int.Parse(e.CommandArgument.ToString().Split(',')[0]);//这里还真必须用单引号来表示字符,而不是""的字符串~,C#的Split就一个以字符,而不是字符串参数的代码
                int itemIndex = int.Parse(e.CommandArgument.ToString().Split(',')[1]);//藏在CommandArgument='<%#Eval("id")+","+(Container as RepeaterItem).ItemIndex%>'逗号后面的参数就是该行行号
                TextBox TextBox1 = Repeater1.Items[itemIndex].FindControl("TextBox1") as TextBox;//获得改行的TextBox1
                TextBox TextBox2 = Repeater1.Items[itemIndex].FindControl("TextBox2") as TextBox;//获得改行的TextBox2
                //这里是修改数据库表的一般逻辑,不赘述了
                if (TextBox1.Text.Trim().Equals("") || TextBox2.Text.Trim().Equals(""))
                {
                    Response.Write("<b>用户名,密码不得为空!</b>");
                }
                else
                {
                    if (db.getBySql("select * from [user_info] where [username]='{0}'", new Object[] { TextBox1.Text }).Rows.Count == 0)//如果没有这个用户名才能修改
                    {
                        db.setBySql("update [user_info] set [username]='{0}' where [id]={1}", new Object[] { TextBox1.Text, id });
                        db.setBySql("update [user_info] set [password]='{0}' where [id]={1}", new Object[] { TextBox2.Text, id });
                        //数据绑定并不意味着会自动刷新Repeater1,必须自己再用代码,刷新一下Repeater1
                        Repeater1.DataSource = db.getBySql("select * from [user_info]");
                        Repeater1.DataBind();
                        Response.Write("<b>已修改!</b>");
                    }
                    else
                    {
                        Response.Write("<b>已有该用户名!</b>");
                    }
                }
            }
            if (e.CommandName == "del")//删除按钮
            {
                db.setBySql("delete from [user_info] where [id]=" + e.CommandArgument);//e.CommandArgument就是藏着该项的数据库id
                //刷新Repeater1
                Repeater1.DataSource = db.getBySql("select * from [user_info]");
                Repeater1.DataBind();
                Response.Write("<b>已删除!</b>");
            }
        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            //添加按钮
            if (TextBox1.Text.Trim().Equals("") || TextBox2.Text.Trim().Equals(""))
            {
                Response.Write("<b>用户名,密码不得为空!</b>");
            }
            else
            {
                if (db.getBySql("select * from [user_info] where [username]='{0}'", new Object[] { TextBox1.Text }).Rows.Count == 0)
                {
                    db.setBySql("insert into [user_info]([username],[password]) values('{0}','{1}')", new Object[] { TextBox1.Text, TextBox2.Text });
                    //刷新Repeater1
                    Repeater1.DataSource = db.getBySql("select * from [user_info]");
                    Repeater1.DataBind();
                    Response.Write("<b>添加成功!</b>");
                }
                else
                {
                    Response.Write("<b>已有该用户名!</b>");
                }
            }
        }
    }
}

可以看到,这里怎么通过CommandName与CommandArgument操纵在Repeater的按钮。

需要注意的是,在Page_Load方法中,Repeater的数据绑定操作,必须放在if (!Page.IsPostBack){}之中,否则会出现如下的错误:


已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页