我有一个.NET(C#)应用程序,必须将其编译为64位。它使用ADO.NET与包括OLEDB的Excel&Access在内的各种数据库一起使用(是的,我知道-Excel不喜欢像被当作数据库那样对待,但是客户确实希望这样做,所以我允许它带有很多警告)< / p>
在我们遇到带有32位Office的系统之前,一切都很好。 64位应用程序不能使用32位OLEDB驱动程序。
现在,使用COM可以进行32位Excel通信。因此,我已经进行了一些测试,并且可以为使用Excel COM的Excel编写替代接口。
因此,我也尝试了Access。此在线的一些描述暗示DAO将起作用。但是,更深入地研究似乎并不正确。 DAO遇到了同样的32位/ 64位问题。
使用Access COM界面,我可以查询表名列表,但仅此而已。例如
Access.Application accessApp = new Access.Application();
accessApp.Visible = false;
accessApp.OpenCurrentDatabase("mydb.accdb", false, "");
Access._CurrentData dt = accessApp.CurrentData;
foreach ( dynamic tbl in dt.AllTables )
{
string name = tbl.Name;
if (! name.StartsWith("MSys"))
Console.WriteLine(">" + tbl.Name+"< ");
}
accessApp.Quit();
这是我所能做的限制吗?我希望能够查询表列及其类型。查询数据行(简单的“获取所有内容”就足够了),并更新行(简单的UPDATE WHERE就足够了)。
我不需要支持JET。
如何在不使用DAO或OLEDB的情况下使用Access COM接口读取数据行并对其进行更新,而这两种方式都不会跨越32位/ 64位边界进行通信?
答案 0 :(得分:1)
很遗憾,您不能这样做。
尽管互操作程序确实有很多技巧,并且使用“编组”形式来允许进程内x64启动+自动执行32位版本的word,或者在这种情况下使用Access,互操作编组系统确实可以不支持数据库引擎。
因此,这是您如何在“如果”可行的情况下编写代码的方法:
Dim accessApp As New Access.Application
accessApp.OpenCurrentDatabase("\\ALBERTKALLAL-PC\test\vbtest\test44.accdb")
Dim strSQL As String
accessApp.Visible = True
Application.DoEvents()
strSQL = "select * from tblHotels3"
Dim rst As Access.Dao.Recordset
Dim strBuf As String = ""
rst = accessApp.CurrentDb.OpenRecordset(strSQL)
Do While rst.EOF = False
strBuf += vbCrLf & rst("ID").Value & "," & rst("HotelName").Value
rst.MoveNext()
Loop
Me.TextBox1.Text = strBuf
accessApp.Quit()
因此,以上代码是在可能的情况下如何使用互操作的方法。
但是,请记住,您需要完整版本的Access才能使用“ createObject()”或创建Access实例。运行时版本不支持此功能(因此,请记住,虽然您已经成功创建了Access实例,但是您无法在运行时中执行此操作。(现在,您显然已经安装了完整版的Access。 )。
并通过创建Access的WHOLE实例,然后所有启动代码以及该Access应用程序的部分将开始运行。最好是简单地创建数据库引擎的实例,这样您就不会启动Access + VBA + WHOLE应用程序。要使用互操作,此代码将起作用:
Dim db As New Access.Dao.DBEngine
Dim MyDatabase As Access.Dao.Database
db.OpenDatabase("\\ALBERTKALLAL-PC\test\vbtest\test44.accdb")
Dim rst As Access.Dao.Recordset
Dim strSQL As String = "select * from tblHotels3"
Dim strBuf As String = ""
rst = db.Workspaces(0)(0).OpenRecordset(strSQL)
Do While rst.EOF = False
strBuf += vbCrLf & rst("ID").Value & "," & rst("HotelName").Value
rst.MoveNext()
Loop
rst.Close()
db.Workspaces(0)(0).Close()
Me.TextBox1.Text = strBuf
但是,再次尝试在.net本地使用数据引擎的那一刻,您就跨进程内(x64)进行了编组,因此上述操作再次将不起作用。
但是,如果要修改文本文件,可以用Word打开文本文档,执行word命令修改文档并保存。从理论上讲,它将在x32 / x64桥接器上工作。
实际上,以下用于Access互操作的代码应该工作,但不能:
Dim accessApp As New Access.Application
accessApp.OpenCurrentDatabase("\\ALBERTKALLAL-PC\test\vbtest\test44.accdb")
Dim strSQL As String
strSQL = "update tblHotels3 set City = 'zoo' "
accessApp.DoCmd.RunSQL(strSQL)
accessApp.Quit()
在上面的注释中,我们尝试使用Access模型进行“更新”。但是,即时Access尝试运行+使用数据库引擎,但失败。上面的示例应该可以工作,但是如果上面的.net(vb.net)代码以x64运行,则发现:
代码确实创建了一个正确的Access实例(.net = x64,Access = x32)。
但是,似乎我们尝试运行+使用Access数据引擎的瞬间,然后.net抛出了错误消息 (因此,上面的内容失败了 accessApp.DoCmd.RunSQL(strSQL) -那就是我们尝试使用数据引擎的时候了。
因此,尽管inter-op可以启动并为您提供Access的运行副本,但尝试使用数据引擎失败。
我确实发现您可以告诉MSAccess运行一些VBA代码。这样就可以了:
Dim accessApp As New Access.Application
accessApp.OpenCurrentDatabase("\\ALBERTKALLAL-PC\test\vbtest\test44.accdb")
accessApp.Visible = True
Application.DoEvents()
MsgBox("access open = ok - show access ok")
accessApp.Run("MyUpdate")
accessApp.Quit()
那么,上面的VBA代码是什么?
Public Sub MyUpdate()
MsgBox "about to update"
CurrentDb.Execute "update tblHotels3 set city = 'zoozoo'"
MsgBox "upate ok"
End Sub
我可以确认上述方法确实有效:
因此,这里的问题是Access数据库引擎被视为并被视为外部数据库对象,并且互操作编组不支持.net的数据库引擎。
解决此问题的唯一方法是安装x64位版本的Access数据引擎。您可以单独安装引擎,而不必安装Access,但是据我所知,.net除非具有x64位版本的数据引擎,否则无法执行此操作。