C#(.Net Core)中连接访问Access数据库

  这里记一下.Net Core访问Access数据库时遇到的坑,查了很多资料。

  注意,我这里是*.mdb,新版Access数据库是*.accdb

  我就不说怎么创建Access数据库了,这里假如我有一个数据库文件(demo.mdb),这个和SQLite很像,就一个单文件,但是我们如果要直接访问这个mdb数据库文件是不行的,但是SQLite确可以。

  我们可以想一下,我们一般连接的数据库是什么样的,都是在服务器上运行了一个进程吧,然后开放端口,我们程序连接到这个端口,提供SQL语句交给进程去执行并返回结果,同样Access数据库也是这样的,这个进程我们可以叫驱动,所以我们首先需要安装Access数据库的环境,那SQLite为什么可以?因为SQLite的驱动就是我们的程序代码。

  Windows下访问Access数据库

  Access大多数时候就是运行在Windows下的,它的驱动也是又微软提供的,下载地址:https://www.microsoft.com/en-us/download/details.aspx?id=54920

  下载安装后,我们就可以在代码中访问了,Windows下我们有两种方法连接:

  System.Data.OleDb

  这种方式是用的最多的,如果我们的程序是运行在Windows平台,就可以采用它,因为它不跨平台,只需要使用NuGet安装System.Data.OleDb依赖包就好了

    public static void Main()
    {
        //我安装的驱动是16.0版本,12.0、10.0版本的
        var connectionString = "provider=Microsoft.ACE.OLEDB.16.0;Data Source=D:\\demo.mdb;";
        using var con = new OleDbConnection(connectionString);
        con.Open();
        using var cmd = con.CreateCommand();
        cmd.CommandText = "SELECT COUNT(*) FROM SYSUSER";
        var data = cmd.ExecuteScalar();
        var count = Convert.ToInt32(data);
        Console.WriteLine("数据总条数:" + count);
    }

  System.Data.Odbc

  采用ODBC访问,和OleDB差不多,只是换个连接方式而已,这种方式可以跨平台,只需要使用NuGet安装System.Data.Odbc依赖包就好了

    public static void Main()
    {
        var connectionString = "Driver={Microsoft Access Driver (*.mdb, *.accdb)}; Dbq=D:\\临时文件\\demo.mdb; Uid = ; Pwd =;";
        using var con = new OdbcConnection(connectionString);
        con.Open();
        using var cmd = con.CreateCommand();
        cmd.CommandText = "SELECT COUNT(*) FROM SYSUSER";
        var data = cmd.ExecuteScalar();
        var count = Convert.ToInt32(data);
        Console.WriteLine("数据总条数:" + count);
    }

   因为ODBC的特性,我们还可以采用DSN的链接方式。首先打开【控制面板】,搜索【ODBC】,然后选择对应位数的数据源,一般是【设置ODBC数据源(64位)】

  imageimage

  【用户DSN】表示当前用户能访问,【系统DSN】就是所有用户能访问,驱动列表里面就是上面连接字符串中Driver字段的名称,我们用【用户DSN】演示,点击【添加】,然后选择【Microsoft Access Driver (*.mdb, *.accdb)】驱动,表示是Access数据库,点击完成,弹出数据库文件的选择框,然后输入【数据源名称】,点击【select】,选择我们的数据库文件(demo.mdb),最后点击OK确认即可。

  imageimage

  最后在【用户DSN】下有一个数据源的记录

  image

  在程序里面访问,只是连接字符串变了而已

    public static void Main()
    {
        //var connectionString = "Driver={Microsoft Access Driver (*.mdb, *.accdb)}; Dbq=D:\\临时文件\\demo.mdb; Uid = ; Pwd =;";
        var connectionString = "DSN=demo";
        using var con = new OdbcConnection(connectionString);
        con.Open();
        using var cmd = con.CreateCommand();
        cmd.CommandText = "SELECT COUNT(*) FROM SYSUSER";
        var data = cmd.ExecuteScalar();
        var count = Convert.ToInt32(data);
        Console.WriteLine("数据总条数:" + count);
    }

  Linux下访问Access数据库

  我这边用的是Ubuntu,找了很多资料,总结了下,大概是这样的。

  首先,前面说了,OleDB不跨平台,所以我们只能用ODBC,那么就需要安装ODBC的驱动:

    sudo apt update
    sudo apt install unixodbc mdbtools odbc-mdbtools

  然后配置ODBC的驱动:sudo vi odbc.ini

    [demo]
    Description=Microsoft Access Database
    Driver=MDBDriver
    ServerName=localhost
    Database =/home/feng/demo.mdb

  说明一下:

    demo:是DSN的名称,连接字符串会用到
    Driver=MDBDriver:的名称是odbcinst.ini配置的节点名称
    ServerName:服务名,一般localhost就可以了
    Database:Access数据库文件的地址
    

  接着配置mdb驱动:sudo vi /etc/odbcinst.ini

  但是配置之前,需要先找到几个odbc动态库的目录,我们可以使用find命令查找一下:sudo find / -name odbc -type d

  image

  找到之后,按自己的位置进行配置:

    [MDBDriver]
    Description=mdb driver
    Driver=/usr/lib/x86_64-linux-gnu/odbc/libmdbodbc.so
    Setup=/usr/lib/x86_64-linux-gnu/odbc/libmdbodbc.so
    FileUsage=1
    UsageCount=1

    [MDBDriverW]
    Description=mdb driver wide
    Driver=/usr/lib/x86_64-linux-gnu/odbc/libmdbodbcW.so
    Setup=/usr/lib/x86_64-linux-gnu/odbc/libmdbodbcW.so
    FileUsage=1
    UsageCount=1

    [ODBC]
    Trace=1
    Tracefile =/tmp/mdb.log

  其实可以这么理解,odbc.ini是配置的DSN,而odbcinst.ini是配置的驱动信息,odbc.iniDriver的节点就是odbcinst.ini中的驱动名称。

  所以,我们同样有两种访问方式:

    public static void Main()
    {
        //可以直接指定驱动
        //var connectionString = "Driver={MDBDriver}; DBQ=/home/feng/demo.mdb;";
        var connectionString = "DSN=demo";
        using var con = new System.Data.Odbc.OdbcConnection(connectionString);
        using var cmd = con.CreateCommand();
        cmd.CommandType = CommandType.Text;
        cmd.CommandText = "SELECT Id,Name FROM SYSUSER";
        con.Open();
        using var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
        while (reader.Read())
        {
            var id = reader.GetInt32(0);
            var name = reader.GetString(1);
            Console.WriteLine($"Id={id},Name={name}");
        }
    }

  吐槽

  你以为到这里就完了么,其实远远还没有!!这里必须吐槽一下,mdbtools这个库给我们在linux下访问Access数据库的一线希望,但是它的不完善与限制又让我们心如死灰!!

  我们看下mdbtools支持的SQL就知道了:

    SQL LANGUAGE
    The currently implemented SQL subset is quite small, supporting only single table queries, no aggregates, and limited support for WHERE clauses. Here is a brief synopsis of the supported language.
    select:   SELECT <top clause> [* | <column list>] FROM <table> WHERE <where clause> <limit clause>
    top clause:   TOP <integer> [ PERCENT ]
    column list:  <column> [, <column list>]
    where clause: <column> <operator> <literal> [AND <where clause>]
    limit clause: LIMIT <integer>
    operator: =, =>, =<, <>, like, ilike, <, >
    literal:  integers, floating point numbers, or string literal in single quotes

  用简单一句话总结就是,mdbtools只支持简单的单表查询,没有聚合函数SUM、COUNT等),没有排序功能(ORDER BY),不得不说,太拉胯了!!!!

  读者可指定通过mdb-sql命令确认:mdb-sql <mdbfile>

  image

  注意:后面的go表示结束,发送sql去执行的意思

  官网对mdb-sql的介绍地址:https://mdbtools.gitlab.io/mdbtools/d6/d38/mdb-sql.html

  跨平台

  虽然mdbtools很拉胯,但是好歹还能用,如果是一些简单的查询,还是可以的,所以这里还是介绍一下跨平台的问题。

  因为这里有ODBCOleDb两种方式访问AccessDB,所以在使用的过程中,我们可以简单封装一下,只需要修改获取连接的方法即可。

  笔者在项目中使用时的封装可以仅供参考

    public override IDbConnection CreateConnection()
    {
        if (OperatingSystem.IsWindows())
        {
            if (ConnectionString.Contains("OLEDB", StringComparison.OrdinalIgnoreCase))
            {
                return new System.Data.OleDb.OleDbConnection(ConnectionString);
            }
        }

        return new System.Data.Odbc.OdbcConnection(ConnectionString)
        {
            ConnectionTimeout = 120,
        };
    }

  代码很简单,就是如果连接字符串中包含了OLEDB且在windows环境,那就使用OleDB连接,否则就是用ODBC

  远程地址

  上面介绍了,我们访问AccessDB,本质上就是访问一个数据库文件,现实场景中,我们访问的文件往往是远程的,那么我们可以采用共享目录(CIFS/SMB)做个网络映射,将远程地址挂着到本地磁盘或者目录,例如:

  Windows下可以采用资源管理器的【映射网络驱动器】来添加,也可以使用命令行添加,如:net use z: \\192.168.139.128\demo /persistent:yes /user:feng 123456

  如果遇到Windows Service或者IIS启动后不能访问的问题,可以参考:关于应用程序采用Windows Service或者IIS启动,无法访问资源管理器创建的网络驱动器(CIFS/SMB)的解决办法

  Linux下就简单了,直接挂着即可,可以参考:Linux挂载文件系统(NFS、CIFS)

 

  总结  

  关于Linux下访问AccessDB,我查过很多材料,目前主流的就两个:mdbtools(ODBC),UcanAccess(java系,还有其他的不常用的包,不得不羡慕下,java生态是真的强!)

  那现在,假如不是java应用,而我们用SQL较为复杂,mdbtools不支持怎么办呢,我建议两个办法:

  1. 写个java控制台程序做中转吧

  2. 使用mdb-schemamdb-export将mdb文件导出成sqlite数据库,再从sqlite中读取(mdb-schemamdb-export,点击查看详细介绍)

    #!/bin/bash

    # 1. 导出mdb表结构为SQLite DDL
    mdb-schema demo.mdb sqlite > schema.sql

    # 2. 导出mdb数据为CSV
    mdb-export demo.mdb table_name > data.csv

    # 3. 创建SQLite数据库并导入数据
    sqlite3 demo.db < schema.sql
    sqlite3 demo.db ".mode csv"
    sqlite3 demo.db ".import data.csv table_name"

  总得来说,AccessDB是Windows下的一个产品,我们尽量不要在Linux下去访问吧

posted @ 2026-01-09 20:13  没有星星的夏季  阅读(8)  评论(0)    收藏  举报