如何编辑 SQL 数据库中网格视图中显示的数据

How to edit the data shown in a grid view from a SQL database

我使用网格视图创建了一个搜索功能,该程序读取用户输入并基于它 returns 从数据库中匹配的数据,但是它 returns 整行,其中包括 2 个我不想显示的 ID 列。听起来很简单,但我似乎找不到任何有关如何执行此操作的教程。

此外,第二列 IdCargo(IdProfession,英文),我想翻译此数据,例如,如果应该出现特定 ID,我想改为显示职业所述员工。我还想显示名称为“Cargo”而不是“IdCargo”的列,而不是“CargaHoraria”我想显示“Carga Horaria”。

如果有人知道使用 GridView 和 SQL 的任何类型的指南或教程,那对未来的研究也将非常有帮助。

太好了。好的,我们不必太担心搜索部分 - 我假设您输入一些带有参数的搜索,结果是数据 table.

现在,我强烈建议您考虑使用列表视图代替网格视图。

至于控制哪些列?好吧,您可以为每一列设置模板。 (这就是我建议列表视图的原因 - 它的标记较少)。

但是,我没有太多的列 - 所以 GV 是“好的”,但是如果你想要更多的列,更多的自定义布局 - 那么 LV 将是 LESS 标记。

LV 的另一个真正大的优势是,您可以让它为您编写标记。

不管怎样,好的,这是我们的GV

非常重要: 每行都有一个 PK 主键(“ID”)。而我们当然不想展示或显示那个 PK ID,但众所周知,PK 是任何数据系统的命脉。因此,GV 中有一个非常酷的功能 - 称为 DataKeys。它允许您 use/have/play PK 行 ID,但您永远不必在 GV 中公开或显示它。 (所以不仅从 UI 的角度来看很好,从安全的角度来看也非常好)。

那么,假设我们有这样的 GV 布局:

    <div style="width:40%;padding:25px">

              <style> .borderhide input {border:none}</style>


        <asp:GridView ID="GVPeople" runat="server" AutoGenerateColumns="False" 
            DataKeyNames="ID" cssclass="table borderhide">
            <Columns>
                <asp:TemplateField HeaderText="First Name">
                    <ItemTemplate>
                        <asp:TextBox ID="FirstName" runat="server" Text='<%# Eval("FirstName") %>' ></asp:TextBox>
                    </ItemTemplate>
                </asp:TemplateField>

                <asp:TemplateField HeaderText="Last Name">
                    <ItemTemplate>
                        <asp:TextBox ID="LastName" runat="server" Text='<%# Eval("LastName") %>' ></asp:TextBox>
                    </ItemTemplate>
                </asp:TemplateField>

                <asp:TemplateField HeaderText="City">
                    <ItemTemplate>
                        <asp:TextBox ID="City" runat="server" Text='<%# Eval("City") %>' ></asp:TextBox>
                    </ItemTemplate>
                </asp:TemplateField>

                <asp:TemplateField HeaderText="Active" ItemStyle-HorizontalAlign="Center">
                    <ItemTemplate>
                        <asp:CheckBox ID="Active" runat="server"
                            Checked='<%# Eval("Active") %>'/> 
                    </ItemTemplate>
                </asp:TemplateField>

                <asp:TemplateField HeaderText="Hotel ID">
                    <ItemTemplate>
                        <asp:TextBox ID="Hotel_ID" runat="server" Text='<%# Eval("Hotel_ID") %>' ></asp:TextBox>
                    </ItemTemplate>
                </asp:TemplateField>

            </Columns>
        </asp:GridView>

我们会感觉到这个带有数据的 GV - 存在更多的列 - 但我们不在乎。

所以,到目前为止我的代码是这样的:

Dim rstData As New DataTable
Dim rstHotels As New DataTable  ' for combo box
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    If Not IsPostBack Then
        LoadGrid()
        ViewState("rstData") = rstData
    Else
        rstData = ViewState("rstData")
    End If

End Sub


Sub LoadGrid()

    rstHotels = MyRst("SELECT ID, HotelName from tblHotels ORDER BY HotelName")
    rstData = MyRst("SELECT * from People Order by FirstName")

    GVPeople.DataSource = rstData
    GVPeople.DataBind()


End Sub

现在我们有了这个:

好的,所以你的问题的一部分是我们显然不想显示 Hotel_id,而是想将其翻译成描述。当然,如果我们要允许编辑,那么让我们将 Hotel_ID 转换为组合框(下拉列表)。和near most/all组合框一样,我们会存储酒店的PK id,但当然会显示酒店名称以方便使用。

因此,代替 hotel_id,我们将标记更改为:

<asp:TemplateField HeaderText="Hotel ID">
    <ItemTemplate>
    <asp:DropDownList ID="cboHotel" runat="server"
        DataTextField="HotelName" 
        DataValueField="ID">
    </asp:DropDownList>
    </ItemTemplate>
</asp:TemplateField>

好的,现在我们必须填充 + 设置组合框。我们有两个任务:

用数据源填充组合框

将组合框设置为每个 gv 行的当前选择。

为此,我们将使用 GV 行数据绑定事件。

因此,我们填写组合的代码如下所示:

所以我们有这个代码:

Protected Sub GVPeople_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GVPeople.RowDataBound

    If e.Row.RowType = DataControlRowType.DataRow Then

        ' get full row of data bind - all columns
        Dim gData As DataRowView = e.Row.DataItem ' NOT A GRID VIEW ROW!!!!!

        ' get combo box
        Dim cboHotels As DropDownList = e.Row.FindControl("cboHotel")
        ' setup cbo data source
        cboHotels.DataSource = rstHotels
        cboHotels.DataBind()
        cboHotels.Items.Insert(0, New ListItem("", ""))   ' add blank (no choice)

        If IsDBNull(gData("Hotel_id")) = False Then
            cboHotels.SelectedValue = gData("Hotel_ID").ToString
        End If

    End If

End Sub

所以,现在我们的结果是这样的:

好的,这样就可以处理您的 questions/issues.

接下来是编辑 - 这真的很酷,也很容易。

好吧,如果你仔细看,我“隐藏”了文本框的边框,但你现在发现你可以像 excel 一样四处移动。一个很好的免费蜜蜂是当文本框有焦点时,它们会显示!!

因此,让我们将我们的按钮放在网格下方以保存编辑。当我四处张望时它看起来像这样:

非常像魔术 - 您现在可以使用 Tab 键 - 几乎像 Excel。您可以选择组合框值。

在上面,我们在 GV 下方放置了一个简单的按钮,如下所示:

        </asp:GridView>
        <asp:Button ID="cmdSave" runat="server" Text="Save Edits" CssClass="btn" />

好的,现在是保存数据按钮。

我们将编写一个辅助例程。将此代码拆分为两个例程的原因有很多。那么第一个套路呢?

它会将网格值发送回我们的 table。如果仔细观察,我将 GV table 数据源保留为 rstData。

因此此例程将网格发送回 table。

Sub GridToTable()

    ' pull GV rows back to table.
    For Each gRow As GridViewRow In GVPeople.Rows

        ' Get database PK value
        Dim PK As Integer = GVPeople.DataKeys(gRow.RowIndex).Item("ID")

        Dim OneDataRow As DataRow = rstData.Select("id = " & PK)(0)

        OneDataRow.Item("FirstName") = CType(gRow.FindControl("FirstName"), TextBox).Text
        OneDataRow.Item("LastName") = CType(gRow.FindControl("LastName"), TextBox).Text
        OneDataRow.Item("City") = CType(gRow.FindControl("City"), TextBox).Text
        OneDataRow.Item("Active") = CType(gRow.FindControl("Active"), CheckBox).Checked

        ' combo box
        Dim cboHotel As DropDownList = gRow.FindControl("cboHotel")
        If cboHotel.Text = "" Then
            OneDataRow("Hotel_ID") = DBNull.Value
        Else
            OneDataRow("Hotel_ID") = cboHotel.SelectedItem.Value
        End If

    Next

End Sub

好的,现在我们要做的就是发送 rstData table(并得到这个:这将处理新行,或编辑!!!!)。

所以,现在我们的保存按钮代码如下所示:

Protected Sub cmdSave_Click(sender As Object, e As EventArgs) Handles cmdSave.Click

    GridToTable()

    Using conn As New SqlConnection(My.Settings.TEST4)
        Using cmdSQL As New SqlCommand("SELECT * from People where ID = 0", conn)

            Dim da As New SqlDataAdapter(cmdSQL)
            Dim daC As New SqlCommandBuilder(da)

            conn.Open()
            da.Update(rstData)

        End Using
    End Using

End Sub

所以请注意我们是如何将整个网格发送回数据库的,所有的更改都是一次性完成的。

最后但同样重要的是:

我使用了一个辅助例程来获取数据 table(一遍又一遍地快速输入那种代码变得非常快,所以我有了这个并且我将它设置为整个应用程序的全局:

Public Function MyRst(strSQL As String) As DataTable

    Dim rstData As New DataTable
    Using conn As New SqlConnection(My.Settings.TEST4)
        Using cmdSQL As New SqlCommand(strSQL, conn)
            conn.Open()
            rstData.Load(cmdSQL.ExecuteReader)
            rstData.TableName = strSQL
        End Using
    End Using

    Return rstData
End Function

注意非常小心,我还将 sql 语句填充到 rst.Table 名称中。 Table 名称并没有真正使用过,但现在因为我坚持使用 SQL table?

那么其实这一行

    Using conn As New SqlConnection(My.Settings.TEST4)
        Using cmdSQL As New SqlCommand("SELECT * from People where ID = 0", conn)

变为:

    Using conn As New SqlConnection(My.Settings.TEST4)
        Using cmdSQL As New SqlCommand(rstData.TableName, conn)

这意味着if/when我说的是子母版,还是多个table的数据要在一个页面上编辑?我使用一个数据集(tables 的集合),并且有一个 routien 将所有 tables 和所有编辑在一个 shot/routine 中发送回数据库。我们没有超过一个 table 的数据要编辑,但这解释了为什么我将 SQL 语句推入数据 table “table” 名称,因为如您所见,那么我们甚至不必重新键入使用的 sql。

注意事项: 我使用的 sql 语句:

SELECT * from People WHERE ID = 0

不是 o 型。我用它来允许 sqlCommandBuilder 为我完成连接和创建 sql 插入和更新蒸汽的所有脏活。