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位)】


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


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

在程序里面访问,只是连接字符串变了而已
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

找到之后,按自己的位置进行配置:
[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.ini中Driver的节点就是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>

注意:后面的go表示结束,发送sql去执行的意思
官网对mdb-sql的介绍地址:https://mdbtools.gitlab.io/mdbtools/d6/d38/mdb-sql.html
跨平台
虽然mdbtools很拉胯,但是好歹还能用,如果是一些简单的查询,还是可以的,所以这里还是介绍一下跨平台的问题。
因为这里有ODBC和OleDb两种方式访问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-schema和mdb-export将mdb文件导出成sqlite数据库,再从sqlite中读取(mdb-schema和mdb-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下去访问吧

浙公网安备 33010602011771号