【问题标题】:How do I properly refresh DataTable from DB (Oracle)如何从 DB (Oracle) 正确刷新 DataTable
【发布时间】:2019-06-08 15:34:00
【问题描述】:

经过大量挖掘,我仍然无法找到在 .NET 中执行以下基本任务的正确方法(也许我只是找不到非常明显的东西,如果是的话,抱歉)。

在 WinForms 应用程序中,有一些 SQL 查询 ("select * from tab1 where col1 > 5");此查询的结果存储在 DataTable-Object 中。

一段时间后,我想刷新数据库中的数据。由于有一个 PrimaryKey,我将DataAdapter.Fill 与表对象一起使用,它确实可以很好地更新值。它做的是删除数据库表中不再存在的行。

请看下面的代码。

    Private connectionString As String = "Data Source=DBName;User Id=my_user;Password=my_pwd;"
    Private Sub LoadData(dt As DataTable, sql As String)
        Using conn = New Oracle.DataAccess.Client.OracleConnection(connectionString)
            Dim cmd = New Oracle.DataAccess.Client.OracleCommand(sql, conn)
            cmd.CommandType = CommandType.Text
            Using da = New Oracle.DataAccess.Client.OracleDataAdapter(cmd)
                conn.Open()
                da.Fill(dt)
                dt.PrimaryKey = New DataColumn() {dt.Columns(0)}
            End Using
        End Using
    End Sub

    Private dt As New DataTable
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

        LoadData(dt, "select * from tab1 where col1 > 5")

    End Sub

EDIT1:创建 DataTable 的新实例或使用它的 Clear-如果对象绑定到网格(当前记录丢失;需要重绘每个单行)。

现在,有一个解决方案,我认为这是一个解决方法

如果我们先将 DataTable-object 中的所有行标记为“已删除”,然后从 DB 中获取所有数据,它会将现有行的状态重置为 Unchanged,将那些不在 DB 上的行保留为 @987654327 @;随后AcceptChanges 将它们从数据表中删除。

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        For Each r As DataRow In dt.Rows
            r.Delete()
        Next
        LoadData(dt, "select * from tab1 where col1 > 5")
        dt.AcceptChanges()

    End Sub

这行得通,但我觉得很难看。

还有一个名为"Database Change Notification"的功能,它非常好,因为它可以让人们知道添加/修改/删除行的rowids,但我们需要显式选择rowid才能删除行来自 DataTable - 这很丑陋(并不总是那么容易)。

这样做的正确方法是什么?

【问题讨论】:

  • 老实说只是刷新,扔掉以前的结果,然后重新加载。在函数调用之前设置 dt = new datatable,在这种情况下,结果将被加载到新的数据表中,或者您可以在重新填充之前调用 dt.clear。
  • @Jeremy 如果 DataTable 绑定到某个网格,这会产生不良的副作用(我在帖子中添加了一个 EDIT 以澄清这一点)。

标签: .net winforms odp.net data-access


【解决方案1】:

这可能是一个更根本的变化,但我认为最好不要使用DataTables,而是使用BindingList。更新列表后,所有更改都会自动反映在 UI 中。

这是一个相当长的例子。使用此方法,列表会从数据库中刷新,但绑定仍然存在,因此您不会更改控件上的数据源。

实现 INotifyPropertyChanged 的​​数据基类:

Public Class INotifyBase
    Implements INotifyPropertyChanged

    Public Sub NotifyPropertyChanged(<CallerMemberName()> Optional ByVal propertyName As String = Nothing)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub

    Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged

End Class

这个例子使用了一个名为 User 的类

Public Class User
    Public Sub New(userID As Integer, userName As String)
        Me.UserName = userName
        Me.UserID = userID
    End Sub

    Public Property UserID As Integer

    Public Property UserName As String

End Class

这是类的绑定列表

Public Class MyUsers
    Inherits BindingList(Of User)

    Public Sub New()
        'TODO Add database code to build list

        'Example list
        Me.Items.Add(New User(1, "Dave"))
        Me.Items.Add(New User(2, "John"))
        Me.Items.Add(New User(3, "Andrew"))

    End Sub

End Class

创建一个类以绑定到 UI。

Public Class UIBinders
    Inherits INotifyBase

    Private _users As MyUsers

    Property Users As MyUsers
        Get
            Return _users
        End Get
        Set(ByVal Value As MyUsers)
            If (_users Is Value) Then Return
            _users = Value
            NotifyPropertyChanged()
        End Set
    End Property

End Class

最后在表单中声明 binder 类并绑定到网格。按钮点击事件加载数据。

Public Class Form1

    Dim Binder As New UIBinders

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
        DataGridView1.DataBindings.Add(New Binding("Datasource", Binder, "Users"))
    End Sub

    Private Sub bnLoadTable_Click(sender As Object, e As EventArgs) Handles bnLoadTable.Click
        Binder.Users = New MyUsers
    End Sub

End Class

我意识到这似乎是一个冗长的示例,对于您最初的问题可能有些过火,但我发现它很有用,因为一旦脚手架到位,其他一切都会自行解决。还将 UI 与业务逻辑分开。

【讨论】:

  • 您能否解释一下使用 BindingList 如何解决从数据库正确更新其内容的问题?
  • 我觉得有误会。我显示的数据存在于 3 个位置:数据库、缓存(在我的示例中为 dt)和 UI(某些网格)。缓存和 UI 之间的连接很好(有一个网格可以用来显示和编辑缓存)。从缓存到数据库的连接也很好。只有要缓存的数据库是不行的,只有当其他人在数据库上删除了一行时。对数据库更改的立即反应也不是必需的,onButtonClick 很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-31
  • 2018-10-09
  • 2021-11-23
相关资源
最近更新 更多