OleDbConnection.Open() 引发的 AccessViolationException

Posted

技术标签:

【中文标题】OleDbConnection.Open() 引发的 AccessViolationException【英文标题】:AccessViolationException thrown by OleDbConnection.Open() 【发布时间】:2021-09-10 20:55:19 【问题描述】:

尝试对我的 OleDbConnection 变量使用 .Open() 方法时出现 System.AccessViolationException 错误。但是,令人困惑的是,当我在另一台计算机上运行我的代码时似乎不会发生这种情况。

我的代码用于我想在服务器上运行的服务。当我在我的个人计算机上运行它时它似乎可以正常工作,但是当我尝试在服务器上运行它时它会引发 AccessViolationException 错误。

代码版本:

我正在使用 C# 在 Windows 10 上使用 Visual Studios 2019 编写代码

OleDbConnection 来自“Assembly System.Data, Version=4.0.0.0”

ADOX 来自“Assembly Interop.ADOX, Version=2.8.0.0”, System.Runtime.InteropServices

ADODB 来自“Assembly Interop.ADODB, Version=2.8.0.0”, System.Runtime.InteropServices

我的代码:

    internal static bool CreateMDB(MySchemaClass schema, string filePath)
    
        OleDbConnection conn = null;
        bool status = true;
        string connectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=0", filePath);

        try
        
            // Setup new file
            catalog.Create(connectionString);
            ((ADODB.Connection)catalog.ActiveConnection).Close();
            conn = new OleDbConnection(connectionString);
            conn.Open(); // <-- Error occurs here

            // Write to new file
            WriteDataToFile(schema, conn);
        
        catch (Exception ex)
        
            status = false;
        
        finally
        
            if (conn != null)
                conn.Close();
        
        return status;
    

堆栈跟踪:

到目前为止我找到的最好的线索是this post,但我对如何从那个起点开始有点模糊。

【问题讨论】:

你创建了什么样的服务项目? 我见过OleDbConnection.Open 抛出的AccessViolationException 的唯一情况是一个完全损坏的mdb 文件。我的提示是,您的 catalog 对象没有被释放,并且新创建的 mdb 文件可能没有完全写入磁盘。尝试在 CreateMDB 方法中创建目录对象,关闭 ActiveConnection 并使用 Marshal.ReleaseComObject 释放catalog,然后再使用 OleDbConnection 打开数据库。 【参考方案1】:

要以编程方式创建 Access 数据库,请执行以下操作

添加对Microsoft ADO Ext. 6.0 for DDL and Security的引用

在VS菜单中,点击Project 选择添加参考 点击COM 检查 Microsoft ADO 分机。 6.0 用于 DDL 和安全性

创建访问数据库

public static string CreateAccessDatabase(string fullyQualifiedAccessFilename, string dbPassword = "")

    string connectionString = String.Format(@"Provider = Microsoft.ACE.OLEDB.12.0; Data Source = 0", fullyQualifiedAccessFilename);

    if (String.IsNullOrEmpty(fullyQualifiedAccessFilename))
    
        throw new Exception("Error (CreateAccessDatabase) - Database filename is null or empty.");
    

    if (!String.IsNullOrEmpty(dbPassword))
    
        connectionString = String.Format(@"Provider = Microsoft.ACE.OLEDB.12.0; Data Source = 0;Jet OLEDB:Database Password='1'", fullyQualifiedAccessFilename, dbPassword);
    
    
    //create new instance
    ADOX.Catalog cat = new ADOX.Catalog();

    //create Access database
    cat.Create(connectionString);

    //close connection
    cat.ActiveConnection.Close();

    //release COM object
    System.Runtime.InteropServices.Marshal.ReleaseComObject(cat);
    GC.Collect();

    cat = null;

    return String.Format("Database created '0'", fullyQualifiedAccessFilename);

用法

string result = string.Empty;

SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "Access Database 2000-2003 (*.mdb)|*.mdb|Access Database 2007 (*.accdb)|*.accdb";

if (sfd.ShowDialog() == DialogResult.OK)

    //create Access database
    result = CreateAccessDatabase(sfd.FileName);

以编程方式在 Access 数据库中创建表

添加 using 语句:

using System.Data.OleDb;

创建表格产品

public static int CreateTableProduct(string fullyQualifiedAccessFilename, string dbPassword = "")

    int result = 0;

    string connectionString = String.Format(@"Provider = Microsoft.ACE.OLEDB.12.0; Data Source = 0", fullyQualifiedAccessFilename);

    if (!String.IsNullOrEmpty(dbPassword))
    
        connectionString = String.Format(@"Provider = Microsoft.ACE.OLEDB.12.0; Data Source = 0;Jet OLEDB:Database Password='1'", fullyQualifiedAccessFilename, dbPassword);
    

    string sqlText = string.Empty;
    sqlText = "CREATE TABLE Product ";
    sqlText += "(ID AUTOINCREMENT not null primary key,";
    sqlText += " Name varchar(50) not null,";
    sqlText += " Price currency, Quantity integer);";

    using (OleDbConnection con = new OleDbConnection(connectionString))
    
        //open connection
        con.Open();

        using (OleDbCommand sqlCmd = new OleDbCommand(sqlText, con))
        
            //execute command
            result = sqlCmd.ExecuteNonQuery();
        
    

    return result;

资源

ADO Features for each Release Which Access file format should I use? CREATE TABLE statement (Microsoft Access SQL) System.Data.OleDb Namespace

【讨论】:

【参考方案2】:

对该问题的令人印象深刻的答案是我的服务器缺少我的个人计算机上的一些文件,并且只需要安装正确的文件。

本例中缺少的部分是 Microsoft Access Database Engine 2016 Redistributable,我最终找到了 here。在我的服务器上运行该可执行文件可以获得所需的文件,之后一切正常。

【讨论】:

以上是关于OleDbConnection.Open() 引发的 AccessViolationException的主要内容,如果未能解决你的问题,请参考以下文章

C# DataTable 更新 Access 数据库

引发异常或引发异常()

引发异常“这是错误”和引发“这是错误”之间的区别? [复制]

使用CAS引发ABA问题

为啥 AWS Lambda 环境中的 EPPlus Excel 库会引发“'Gdip' 的类型初始化程序引发异常”

类型初始值设定项引发异常