如何使用 Windows 窗体中的 Access 附件字段?

Posted

技术标签:

【中文标题】如何使用 Windows 窗体中的 Access 附件字段?【英文标题】:How to work with Access attachment field from Windows Forms? 【发布时间】:2020-08-15 00:02:54 【问题描述】:

在 Visual Studio 中,我从本地 Access 数据库文件设置数据源。除其他外,该数据库中的一个表具有多个不同的附件字段(使用 Access 的附件数据类型)。

首先, Visual Studio 将它们标记为字符串数据类型,这似乎不正确,但是当我去更改它时,似乎没有适用的数据类型: Visual Studio data types

选择什么数据类型合适?

其次,什么控件适合在表单上表示此字段?显然 TextBox 不会削减它,但我不知道让用户上传和下载这些附件的最佳方式是什么 - 我对 winforms 很陌生。

如果编码是您的答案的一部分,请注意我使用的是 VB.net(我知道,我知道)。 Visual Studio 版本为 Community 2019 Edition 16.7.1

【问题讨论】:

内置数据 UI 都不适合附件数据类型。您必须手动创建一个自定义控件来处理它可能包含的多个文件,store 和 read。 那些帖子建议使用 DAO 对象模型。 一种查询隐藏子表的方法(访问中的附件列是多值的 - 您可以为该给定列有 1 或 15 个附件)在幕后是一个常规访问表。如果您使用下面的提示,那么您不必使用 DAO 文件保存/写入,而是可以像使用 varbinary 一样使用 sql server 进行写入。 ACE 查询处理器可以公开额外的列,这通常在 Access 中完成,事实证明,相同的方法在 .net 和 oleDB 中也适用,如下所示。 【参考方案1】:

一个非常有趣的问题。

答案是肯定的,您可以轻松提取附件数据。

首先要意识到附件表实际上是在“幕后”一个普通的简子表。请记住,附件列(子表)可以附加 1 或 15 个文件。

破解这个魔法的诀窍是在 Access 中启动查询生成器,然后放入该表中。

你看这个

注意每个附件(3 列)如何存在一组“列”。

现在,如果在查询中您不包括 3 列之一?然后查询中的每一行得到 1 行。

以上,我们走吧

从 tblAttach 中选择 *。

我在这张表中只有一行,但是你可以看到两个附件!!

现在是魔术:

如果您包含任何子表列,那么数据引擎将在后台执行此隐藏子表的 LEFT JOIN(事实上,它不再隐藏了!!!)。

所以,我们可以对查询执行此操作:

SELECT ID, FirstName, LastName, 
MyBinFiles.FileName, 
MyBinFiles.FileType, 
MyBinFiles.FileData
FROM tblAttach;

因此,仅包含任何一个子列名称都会导致 Access(ACE) 进行左连接。 (您不使用连接 - 只是出现的 3 列中的任何一个的 ACT 都会导致访问左连接)。

因此,父列(id、FirstName、LastName)将为附件表中的每个子行“重复”(该表隐藏在 Access 中 - 您无法获取名称,但有了这个技巧,好吧 -我们不在乎。

你现在明白了:

那个文件数据列呢?它是整个文件的 bytes() 数组。

那么,现在,让我们跳转到 .net。

拖放到网格视图中。我们有这个代码

然后是一个按钮 - 该按钮后面的代码是这样的:

   Dim con As New OleDb.OleDbConnection(My.Settings.Test44)

    Dim strSQL As String
    strSQL = "SELECT ID, FirstName, LastName, " &
             "MyBinFiles.FileName," &
             "MyBinFiles.FileType" &
             " FROM tblAttach"

    ' "tblAttach.MyBinFiles.FileData," &

    Dim oReader As New OleDb.OleDbDataAdapter(strSQL, con)
    Dim rstData As New DataTable
    oReader.Fill(rstData)

    Me.DataGridView1.DataSource = rstData

    Dim btn As New DataGridViewButtonColumn()
    DataGridView1.Columns.Add(btn)
    btn.HeaderText = "Export"
    btn.Text = "Export File"
    btn.Name = "btn"
    btn.UseColumnTextForButtonValue = True

好的,我们现在在 .net 中有这个:

(再次注意 - 两行!!! - 发生了 MAGIC 连接!!!)

现在,导出文件的按钮代码?

我们有这个:

Private Sub DataGridView1_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellClick

    If e.ColumnIndex = 5 Then
        ' export data
        With DataGridView1.Rows(e.RowIndex)

            Call ExportFile(.Cells(0).Value, .Cells(3).Value, .Cells(4).Value)

        End With
    End If

End Sub

请注意,子表的 PK 列未公开。实际上主表的PK(id)+文件名=整行的PK。

是的,这确实意味着您不能将两个同名文件附加到给定的单行 - Access 中不允许这样做 - UI 和引擎会阻止这种情况。

所以,在上面,我传递了 ID 和文件名。 而且我没有在显示网格查询中包含二进制(byte())列 - 它会导致“讨厌” - 但是如果附件是图片? 那么是的,从 SQL 服务器(或 Access/ACE)中提取/显示二进制图片的代码示例实际上可以工作。

在我的示例中,您可以看到文件扩展名是 pdf(因此类型列是原始文件扩展名 - 在大多数情况下!!!)。因此,pdf文件被存储在这里。

那么,现在将那个附件导出到标准 Windows 文件的代码?

代码实际上与使用 SQL Server 和 varbinary 列执行此操作时相同。

我们得到这个:

Sub ExportFile(id As Integer, strFile As String, strType As String)

    Dim con As New OleDb.OleDbConnection(My.Settings.Test44)

    Dim strSQL As String
    strSQL = "SELECT ID, " &
             "MyBinFiles.FileName," &
             "MyBinFiles.FileType," &
             "MyBinFiles.FileData" &
             " FROM tblAttach " &
             " WHERE ID = " & id &
             " AND MyBinFiles.FileName = '" & strFile & "'"

    Dim oReader As New OleDb.OleDbDataAdapter(strSQL, con)
    Dim rstData As New DataTable
    oReader.Fill(rstData)

    Dim strSaveAsFile As String = "c:\test\Files\" & strFile & "." & strType
    Dim bytefile As Byte() = rstData.Rows(0).Item("MyBinFiles.FileData")
    File.WriteAllBytes(strSaveAsFile, bytefile)

End Sub

所以,请注意这次我们确实包含了 FileData。请注意我是如何将数据 (byte()) 数组写入磁盘的。

最终结果将是您可以打开的工作 Windows 文件。在我的例子中是 pdf,但它可能是一张图片,或者说一个 word 文件。

【讨论】:

应该重新打开问题以允许将此答案标记为答案。 我之前尝试过类似的方法,但遇到了 Access 压缩数据的文件(例如 bmp、tiff、可以找到here 的列表)。您能否检查一下您当前的方法是否适用于这些文件类型? @ErikA 的进一步评论 - PDF 文件是一个特例。详情请见this answer。 谢谢戈德。虽然我的代码确实有效,但看起来 byte() 数组必须由 ACE 解压缩才能真正起作用。因此,我的示例确实适用于 PDF 文件,但这只是因为 PDF “更宽容”。我将在一段时间内使用工作代码编辑和更新我的帖子。获取列和额外行的提示/技巧对于多值列仍然很方便,但公平地说,在附件的情况下,压缩问题就会发挥作用。 (事实上​​,似乎上面总是解压缩文件 - 所以它可以工作。但对于压缩格式,它失败了,因为它也解压缩了

以上是关于如何使用 Windows 窗体中的 Access 附件字段?的主要内容,如果未能解决你的问题,请参考以下文章

pywin32 怎么获取 windows 的窗体内文本框的内容

使用 C# windows 窗体向 Ms Access 数据库插入新记录时出现语法错误

如何在Pycharm中运用PyQT5创建Windows窗体

如何在 Access 2007 的窗体中实现点击按钮打开另一个窗体???

使用 installshield 创建安装文件时 Windows 窗体的 Microsoft Access 数据库的位置

如何使用 access 数据库中的值填充列表或数组