.net 如何使用Windows窗体中的Access附件字段?
在VisualStudio中,我从本地Access数据库文件设置了数据源。该数据库中的一个表具有多个不同的附件字段(利用Access的附件数据类型) 首先,Visual Studio将它们标记为字符串数据类型,这似乎不正确,但当我要更改它时,似乎没有适用的数据类型: 要选择的合适数据类型是什么 其次,什么控件适合在表单上表示此字段?很明显,文本框并不能解决这一问题,但我不知道让用户上传和下载这些附件的最佳方式是什么——我对winforms很陌生.net 如何使用Windows窗体中的Access附件字段?,.net,vb.net,visual-studio,winforms,ms-access,.net,Vb.net,Visual Studio,Winforms,Ms Access,在VisualStudio中,我从本地Access数据库文件设置了数据源。该数据库中的一个表具有多个不同的附件字段(利用Access的附件数据类型) 首先,Visual Studio将它们标记为字符串数据类型,这似乎不正确,但当我要更改它时,似乎没有适用的数据类型: 要选择的合适数据类型是什么 其次,什么控件适合在表单上表示此字段?很明显,文本框并不能解决这一问题,但我不知道让用户上传和下载这些附件的最佳方式是什么——我对winforms很陌生 如果编码是您答案的一部分,请注意我正在使用VB.
如果编码是您答案的一部分,请注意我正在使用VB.net(我知道,我知道)。Visual Studio版本是社区2019版16.7.1一个非常有趣的问题 答案是肯定的,你可以很容易地提取附件数据 首先要认识到的是,附件表实际上是“幕后”一个普通的jane子表。请记住,该附件列(子表)可以附加1个或15个文件 破解这一魔法的诀窍是在Access中启动查询生成器,然后放入该表 你看到了吗 请注意每个附件(3列)如何存在一组列 现在,如果在查询中不包括这3列中的一列,您会这样做吗?然后,查询中的每一行对应一行 有了,上面,我们走吧 从tblAttach中选择* 我在这个表中有一行,但是你可以看到两个附件 现在是魔术: 如果包含任何子表列,那么数据引擎将在幕后执行此隐藏子表的左联接(事实上,它不再隐藏!!!) 因此,我们可以对查询执行以下操作:
SELECT ID, FirstName, LastName,
MyBinFiles.FileName,
MyBinFiles.FileType,
MyBinFiles.FileData
FROM tblAttach;
因此,只要包含任何一个子列名,Access(ACE)就会进行左连接。(您不使用联接-只需显示3列中的任意一列,即可访问左联接)
因此,父列(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中有了这个:
(再次注意-两行!!!-因此发生了魔术连接!!!)
现在,导出文件的按钮代码是什么
我们有:
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和文件名。
我没有在显示网格查询中包含binary(byte())列-这会导致“讨厌”-但是如果附件是图片?
那么是的,从SQLServer(或Access/ACE)中提取/显示二进制图片的代码示例实际上可以工作
在我的示例中,您可以看到文件扩展名是pdf(因此类型列是原始文件扩展名-在大多数情况下!!!)。因此,pdf文件存储在这里
那么,现在的代码是将一个附件导出到一个标准windows文件吗
代码实际上与使用SQLServer和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文件。内置的数据UI都不适合附件数据类型。您必须创建一个自定义控件来处理它可能包含的多个文件,并手动处理它们。这些帖子建议使用DAO对象模型。有一种方法可以查询隐藏的子表(access中的附件列是多值的-对于给定的列,您可以有1个或15个附件)在后台有一个常规的访问表。如果您使用下面的提示,那么您不必使用DAO文件保存/写入,而是可以像在sql server中使用varbinary一样进行写入。ACE查询处理器可以公开额外的列,并且通常在access中完成,而在.net中使用oleDB a也可以使用相同的方法s如下所示。应重新打开该问题,以便将此答案标记为答案。我以前尝试过类似的方法,但在Access压缩数据的文件中遇到了问题(例如,bmp、tiff、可以找到的列表)。您能检查一下您当前的方法是否适用于这些文件类型吗?@ErikA的进一步评论–PDF文件是一个特例。有关详细信息,请参阅。谢谢Gord。虽然我的代码确实有效,但看起来byte()数组必须由ACE进行反压缩才能真正有效。因此,我的示例适用于PDF文件,但这只是因为PDF是“更宽容”。我会在一段时间内,编辑和更新我的文章,使用工作代码。获取列和额外行的技巧对于多值列仍然很方便,但公平地说,对于附件,压缩问题就开始发挥作用了。(事实上,上面的代码似乎总是对文件进行反压缩,所以它可以工作。但是对于压缩格式,它失败了,因为它也进行了解压缩。)