65.9K
CodeProject 正在变化。 阅读更多。
Home

更新多个字段的模式

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.56/5 (3投票s)

2005 年 4 月 14 日

4分钟阅读

viewsIcon

40331

一篇介绍如何只更新网页表单中已更改的特定值的模式的文章。

引言

您经常会发现自己需要将网页表单中的值更新到数据库中。这通常是一个直接的过程。但是,如果您只想更新网页表单中已更改的那些值,会发生什么?并且,考虑到将来需要更新的值集可能会增加(或不太可能减少),您是否想要一个易于使用的模式?在此示例中,我将介绍更新个人信息的案例。

背景

可能您有一个用户可以更新其个人信息的表单。无论您使用的是 Windows Forms 还是 Web Forms(在此示例中我将使用 Web Forms),您都会使用一系列 Web 控件来捕获数据(下拉列表、文本框、单选按钮等)。而且,您可能不想更新存储此信息的表中的每个值,因为存在某些触发器会在值更新时执行某些操作。或者,您可能有大量的访问量,只是不想让事务日志填满。或者,您的用户可能智力有限,即使他们没有更新任何内容也经常点击“提交”按钮,而您不想不加限制地发出调用。以下解决方案将尝试提供一种处理这种情况的模式。

使用代码

该方法论基本上是维护一个参数名称/参数值的哈希表,只考虑在网页表单中已更改的那些值。通过填充我们声明的 System.Web.UI.Page 类实例变量,我们可以将此值传递给负责发出数据库更新调用的某个方法。此更新方法将提取这些参数名称和值,并发出对负责更新的存储过程的调用。

执行此操作的代码如下:

  1. 创建一个 System.System.Collections.Hashtableprivate 实例变量。此变量将负责将存储过程参数名称与用户新创建的(并且保证不同的 - 稍后会详述)值关联起来。
    private System.Collections.Hashtable _changeList;
  2. 创建一个 private 实例方法,该方法使用上面提到的键/值参数填充表。
    private void Add2Collection(string name, string newValue) 
    {
        if(null == _changeList) 
        {
            //must issue the constructor here.
    
            //We want _changeList to be null if nothing changed.
    
            _changeList = new Hashtable();    
                                                      
        }
        _changeList.Add(name, newValue);
    }
  3. 连接每个 Web 控件的 ValueChanged 事件。例如:
    System.Web.UI.WebControls.TextBox = TextChanged
    System.Web.UI.WebControls.DropDownList = SelectedIndexChanged 
    System.Web.UI.WebControls.CheckBox = CheckedChanged

    现在,aspx 标记应该看起来像这样:

    Name 
        <asp:TextBox id="txtName" runat="server" 
              OnTextChanged="txtName_Changed"/>
    Age
        <asp:DropDownList id="cmbAge" runat="server" 
            OnSelectedIndexChanged="cmbAge_Changed">
            <asp:ListItem Value="0">13-20</asp:ListItem>
            <asp:ListItem Value="1">21-30</asp:ListItem>
            <asp:ListItem Value="2">31-40</asp:ListItem>
            <asp:ListItem Value="3">41-50</asp:ListItem>
            <asp:ListItem Value="4">>

    请注意,我没有为 rbFemale 单选按钮设置事件。这是因为它们都是同一组的成员,并且我断言存储此字段的表定义如下:

    CREATE TABLE UserData 
    (
        ...
        UserName varchar(50),
        Age int,
        IsMale bit,
        ...
    )

    因此,如果用户是男性并单击 rbFemale,这将触发对 rbMale_Changed() 的调用。如果用户是女性并单击 rbMale,同样会发出对 rbMale_Changed() 的调用。希望没有人会经历太多的性别转变。

  4. 在每个事件中,发出对 Add2Collection() 的调用。
    public void txtName_Changed(object sender, EventArgs e) 
    {
        Add2Collection("userName", txtName.Text);
    }
    
    public void cmbAge_Changed(object sender, EventArgs e) 
    {
        Add2Collection("userAge", cmbAge.SelectedValue);
    }
    
    public void rbMale_Changed(object sender, EventArgs e) 
    {
        Add2Collection("isMale", rbMale.Checked.ToString());
    }

    这就是我们如何保证当没有任何更改时 _changeList 将为 null。只有对 Add2Collection 的调用才会初始化此变量。如果没有更改,那么此变量将保持 null,并向我们发出标志,表明我们不需要调用数据库。

  5. 最后,还有一个按钮可以发出更新调用:
    <asp:Button id="btnUpdate" runat="server" 
      Text="Update" OnClick="btnUpdate_Click"/>

    以及其背后的代码:

    public void btnUpdate_Click(object sender, System.EventArgs e)
    {
        Update(_changeList);
    }

    更新方法非常简单。它接受 _changeList,或者在本例中是实现 IDictionary 的类。这些条目现在保证包含参数名称及其值。我们使用枚举器提取这些对,以收集参数名称和参数值,将它们加载到 SqlCommand 中并发出调用。当然,如果 IDictionary 对象为 null,我们只需返回。

    private static void Update(IDictionary parameterCollection) 
    {
           //user hit update but didn't update anything - just return
    
        if(null == parameterCollection) 
        {
            return;
        }
    
        const string sproc = "SomeUpdateSproc";
        using(SqlConnection connection = 
                new SqlConnection(SomeConnectionString))
        using(SqlCommand command = 
                new SqlCommand(sproc, connection)) 
        {
            command.CommandType = CommandType.StoredProcedure;
            
            //get every name/value pair
    
            foreach(DictionaryEntry entry in parameterCollection) 
            {
              //don't forget to add the '@'
    
              SqlParameter parameter = 
                command.Parameters.Add("@" + entry.Key, entry.Value);  
              parameter.Value = entry.Value;  //our new value!
    
            }
    
            command.Connection.Open();
            command.ExecuteNonQuery();
            command.Connection.Close();
        }
    }

    我将此方法设为 static 并将实例变量作为参数接受,因为这将封装在一些数据访问层代码中。只需将其移出代码隐藏页,放入数据访问层即可。

    最后,存储过程将如下所示:

    CREATE PROCEDURE [dbo].[SomeUpdateSproc] 
    
        @userName varchar(50) = null,
        @userAge int = null,
        @isMale bit = null
    
    AS
    
    if @userName <> null begin
        --do some update
    
    end
    
    if @userAge <> null begin
        --do some update
    
    end
    
    if @isMale <> null begin
        --do some update
    
    end
    
    GO

就这样。随着新的字段被添加到需要以相同方式更新的表中,只需添加相应的 Web 控件,设置其 Changed 事件处理程序,发出 Add2Collection() 调用,并向存储过程添加适当的逻辑。

历史

目前还没有。

© . All rights reserved.