替换 DataReader 数据

Replace DataReader data

我正在开发 ASP.Net Web 窗体 Application.Currently SqlDataReaders 直接绑定到两个网格视图。我需要在将数据集绑定到网格视图之前更改数据集。有两个数据集来自存储过程(两个 select 查询)。在绑定到网格之前,我需要编辑它们并替换一些数据。实现此目的的最佳方法是什么?

private void BindTable()
{
    LiteralMessage.Text = "";
    RecentLiteralMessage.Text = "";
    ErrorLiteralMessege.Text = "";
    var isStandbySelected = SelectedDatabase.SelectedValue == "stats";
    using (var db = new Database(isStandbySelected))
    {
        try
        {
            
            //db.BeginTransaction(IsolationLevel.Snapshot);
            db.BeginTransaction(); //Need a transaction block to stop from closing connection
            db.StoredProcedure = "dbo.NewExportList";
            if (!string.IsNullOrEmpty(TextBoxNameFilter.Text))
                db.AddParameter("@nameFilter", TextBoxNameFilter.Text);
            db.AddParameter("@excludedExports", CheckBoxExcludedExports.Checked);
            db.AddParameter("@RunOnReportingServer", SelectedDatabase.SelectedValue == "stats" );
            if(CheckBoxRecentlyRun.Checked)
                db.AddParameter("@recentExports", true);

            System.Data.SqlClient.SqlDataReader reader = db.GetDataReader();
            GridViewExports.DataSource = reader;

            GridViewExports.DataBind();
            if (GridViewExports.Rows.Count > 0)
            {
                GridViewExports.Visible = true;
            }
            else
            {
                GridViewExports.Visible = false;
                LiteralMessage.Text = "No Results";
            }
             
    
            GridViewRecentExports.DataSource = null; //clear any exsisting data

            if (reader.NextResult()) //Get the second data set if any
            {
                GridViewRecentExports.DataSource = reader;                        
            }

            GridViewRecentExports.DataBind();

            if (GridViewRecentExports.Rows.Count > 0)
            {
                GridViewRecentExports.Visible = true;
            }
            else
            {
                GridViewRecentExports.Visible = false;
                RecentLiteralMessage.Text = "No Results";
            }
            db.CloseConnection();
            //db.CommitTransaction();
        }
        catch (Exception ex)
        {
      
        }
    }

好的,这里有两种常用的方法。

首先,让我们拿一个示例 GV,并通过这里的两个常见方法来工作。

我们的简单标记:

    <asp:GridView ID="GridView1" runat="server" 
        AutoGenerateColumns="False" DataKeyNames="ID" CssClass="table">
        <Columns>
            <asp:BoundField DataField="FirstName" HeaderText="FirstName"     />
            <asp:BoundField DataField="LastName" HeaderText="LastName"       />
            <asp:BoundField DataField="HotelName" HeaderText="HotelName"     />
            <asp:BoundField DataField="Description" HeaderText="Description" />
            <asp:BoundField DataField="Nights" HeaderText="Nights"  ItemStyle-HorizontalAlign="Center"          />
            <asp:BoundField DataField="Price" HeaderText="Price"  DataFormatString="{0:c2}" 
                ItemStyle-HorizontalAlign="Right" />
        </Columns>
    </asp:GridView>

好的,我们要加载的代码:

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
            LoadGrid();
    }

    void LoadGrid()
    {
        DataTable rstData = new DataTable();
        using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
        {
            string strSQL = "SELECT * FROM tblHotels ORDER BY HotelName";
            using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn)) {
                conn.Open();
                rstData.Load(cmdSQL.ExecuteReader());
            }
        }

        GridView1.DataSource = rstData;
        GridView1.DataBind();
    }

好的,我们现在有这个:

所以,在上面,我们说要显示每行预订的总价。

所以,让我们在这里使用“通用”方法。我们首先将我们的额外控件添加到网格视图。让我们使用平面简文本框:

例如:这个:

            <asp:BoundField DataField="Price" HeaderText="Price"  DataFormatString="{0:c2}" 
                ItemStyle-HorizontalAlign="Right" />

            <asp:TemplateField HeaderText="Total">
                <ItemTemplate>
                    <asp:Label ID="lblTotal" runat="server"></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>

所以,我们刚刚给 gv 添加了一个标签。

因此,我们使用的事件是行数据绑定事件。这甚至很棒,因为它为我们提供了一个数据行和一个网格视图行。此事件也非常适合更改行或文本框的颜色,当然还可以进行一些计算或设置 un-bound 控件的值 - 例如我们的标签

所以,现在在我们的行数据绑定事件中,我们可以这样做:

    protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            DataRowView gData = (DataRowView)e.Row.DataItem;
            Label lblTotal = e.Row.FindControl("lblTotal") as Label;
            decimal MyPrice = (int)gData["Nights"] * (decimal)gData["Price"];
            lblTotal.Text =  string.Format("{0:c2}", MyPrice);
        }
    }

现在我们的腰带是这样的:

好的,以上是常用的做法

然而,一个有趣的方法?

一旦您填写了数据 table,您就可以自由地处理该 table,甚至包括向 table 添加新列!!!

所以,让我们转储(删除)我们的数据绑定行事件。

让我们更改标签以使用来自 table 的绑定数据。所以,我们的标记现在是:

            <asp:TemplateField HeaderText="Total">
                <ItemTemplate>
                    <asp:Label ID="lblTotal" runat="server"
                        Text = '<%# string.Format("{0:c2}", Eval("MyTotal")) %>'
                        ></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
    </asp:GridView>

现在,我们在数据 table 中没有名为 MyTotal 的列,对吗?

但是,我们可以在从查询或存储过程中获取 table 之后添加 table.

所以,我们的网格加载代码现在变成了这样:

        DataTable rstData = new DataTable();
        using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
        {
            string strSQL = "SELECT * FROM tblHotels ORDER BY HotelName";
            using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn)) {
                conn.Open();
                rstData.Load(cmdSQL.ExecuteReader());
            }
        }

        rstData.Columns.Add("MyTotal", typeof(decimal));

        foreach (DataRow MyRow in rstData.Rows)
        {
            MyRow["MyTotal"] = (int)MyRow["Nights"] * (decimal)MyRow["Price"];
        }

        GridView1.DataSource = rstData;
        GridView1.DataBind();
    }

请注意我们是如何添加一个新列,然后执行 table 流程循环来设置该值的。因此GV的结果是一样的。

最后一点?

很少有人意识到数据 table 支持表达式!!! 当您修改值等时,更新会自动进行。那么,代替上面的行处理循环?我们实际上可以这样做:

        DataColumn MyCol = new DataColumn("MyTotal", typeof(decimal));
        MyCol.Expression = "[Nights] * [Price]";
        rstData.Columns.Add(MyCol);

        GridView1.DataSource = rstData;
        GridView1.DataBind();

所以,在大多数情况下,我经常只使用行数据绑定。而且这个事件很好,因为你不写循环,对于条件格式,比如行颜色变化,或者 column/cell 颜色格式等,或者新文本框的新设置?行数据绑定很好。

但是,您也可以如前所述,添加列,然后循环 + 处理数据 table,您甚至可以添加基于其他列的表达式的列。然后您将更新后的 pre-processed table 正常发送到 gridview。

另请注意,当我使用查询时,存储过程的工作方式相同:

例如:

        using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
        {
            using (SqlCommand cmdSQL = new SqlCommand("MyStoreProcedure", conn)) {
                cmdSQL.CommandType = CommandType.StoredProcedure;
                cmdSQL.Parameters.Add("@Active", SqlDbType.Bit).Value = 1;
                conn.Open();
                rstData.Load(cmdSQL.ExecuteReader());
            }
        }

        DataColumn MyCol = new DataColumn("MyTotal", typeof(decimal));
        MyCol.Expression = "[Nights] * [Price]";
        rstData.Columns.Add(MyCol);

        GridView1.DataSource = rstData;
        GridView1.DataBind();