本页的多数据源指:在同一个 .NET Framework 4.8 项目里,使用同一种 Access 引擎(OleDb + Jet 或 ACE),同时打开多个不同的库文件(例如 orders.mdbinventory.mdb)。每个文件对应各自的连接字符串与 OleDbConnection,不是一条连接串连所有库。操作文案以 LCode 为准;代码均为 C# 5.0 与 VB.NET。单库 CRUD 见 数据库 · Access;网格 UI 见 数据表单与自定义列

和「一张库里多张表」的区别:多表仍在同一个 .mdb/.accdb 里,用一个连接即可。多数据源是多个物理库文件,必须多套连接。

典型场景

场景 库文件示例 说明
业务拆库 orders.mdb + customers.mdb 订单与客户分文件,便于备份或权限隔离
主库 + 配置库 appdata.mdb + config.mdb 配置可单独替换,不影响业务数据
主库 + 日志库 main.mdb + logs.mdb 日志膨胀时只归档/清空日志库

在 LCode 中准备

  1. 窗体项目确认已引用 System.Data(OleDb)。Jet 连 .mdb 时工程宜 x86(或 AnyCPU + 首选 32 位);ACE 须与进程位数一致。细节见 Access 专页。
  2. 把多个库文件放到输出目录旁,例如 Data\orders.mdbData\inventory.mdb(路径可按项目约定调整)。
  3. 为每个文件各写一条连接字符串(同一 Provider,不同 Data Source)。
  4. 在 LCode 中 编译 → 编译解决方案F8),再运行验证每个文件都能 Open
不要:把两个文件路径拼进同一条连接串;也不要用同一个已打开的 OleDbConnection 去「切换」到另一个文件——应关闭后换连接串,或同时持有两个连接对象。

多条连接字符串(同一 Provider)

下面以 Jet + 两个 .mdb 为例;若用 ACE / .accdb,只需改 Provider 与扩展名,仍保持「一文件一串」。

C#
using System.Data.OleDb;
using System.IO;
using System.Windows.Forms;

string ordersPath = Path.Combine(Application.StartupPath, "Data", "orders.mdb");
string inventoryPath = Path.Combine(Application.StartupPath, "Data", "inventory.mdb");

// 同一 Provider,不同 Data Source = 两个数据源
string ordersConnStr =
    "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + ordersPath + ";";
string inventoryConnStr =
    "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + inventoryPath + ";";
VB.NET
Imports System.Data.OleDb
Imports System.IO
Imports System.Windows.Forms

Dim ordersPath As String = Path.Combine(Application.StartupPath, "Data", "orders.mdb")
Dim inventoryPath As String = Path.Combine(Application.StartupPath, "Data", "inventory.mdb")

Dim ordersConnStr As String =
    "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & ordersPath & ";"
Dim inventoryConnStr As String =
    "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & inventoryPath & ";"

实例:分别查询两个 Access 库

假定 orders.mdb 有表 Orders(字段 IdCustomerName),inventory.mdb 有表 Stock(字段 SkuQty)。在按钮点击中各读一次,再汇总提示。参数均用 OleDb 的 ?

C#
string customer = null;
using (OleDbConnection ordersConn = new OleDbConnection(ordersConnStr))
{
    ordersConn.Open();
    using (OleDbCommand cmd = new OleDbCommand(
        "SELECT TOP 1 CustomerName FROM Orders WHERE Id = ?", ordersConn))
    {
        cmd.Parameters.AddWithValue("@p1", 1);
        object o = cmd.ExecuteScalar();
        if (o != null && o != DBNull.Value)
            customer = o.ToString();
    }
}

int qty = 0;
using (OleDbConnection invConn = new OleDbConnection(inventoryConnStr))
{
    invConn.Open();
    using (OleDbCommand cmd = new OleDbCommand(
        "SELECT TOP 1 Qty FROM Stock WHERE Sku = ?", invConn))
    {
        cmd.Parameters.AddWithValue("@p1", "A001");
        object o = cmd.ExecuteScalar();
        if (o != null && o != DBNull.Value)
            qty = Convert.ToInt32(o);
    }
}

MessageBox.Show(
    "订单客户:" + (customer ?? "(无)") +
    "\n库存 A001:" + qty.ToString());
VB.NET
Dim customer As String = Nothing
Using ordersConn As New OleDbConnection(ordersConnStr)
    ordersConn.Open()
    Using cmd As New OleDbCommand(
        "SELECT TOP 1 CustomerName FROM Orders WHERE Id = ?", ordersConn)
        cmd.Parameters.AddWithValue("@p1", 1)
        Dim o As Object = cmd.ExecuteScalar()
        If o IsNot Nothing AndAlso o IsNot DBNull.Value Then
            customer = o.ToString()
        End If
    End Using
End Using

Dim qty As Integer = 0
Using invConn As New OleDbConnection(inventoryConnStr)
    invConn.Open()
    Using cmd As New OleDbCommand(
        "SELECT TOP 1 Qty FROM Stock WHERE Sku = ?", invConn)
        cmd.Parameters.AddWithValue("@p1", "A001")
        Dim o As Object = cmd.ExecuteScalar()
        If o IsNot Nothing AndAlso o IsNot DBNull.Value Then
            qty = Convert.ToInt32(o)
        End If
    End Using
End Using

Dim customerText As String = "(无)"
If Not String.IsNullOrEmpty(customer) Then customerText = customer
MessageBox.Show(
    "订单客户:" & customerText &
    vbCrLf & "库存 A001:" & qty.ToString())

分别绑定到两个 DataGridView

界面可放 dgvOrdersdgvStock,各自 Fill 到自己的 DataTable。Access 不能用一条 SQL 直接 JOIN 两个不同的 .mdb 文件(除非做链接表等高级手法);业务关联请在代码里用键拼接,或把需要关联的表放进同一库文件。

C#
using System.Data;

DataTable dtOrders = new DataTable();
using (OleDbConnection c = new OleDbConnection(ordersConnStr))
using (OleDbDataAdapter da = new OleDbDataAdapter(
    "SELECT Id, CustomerName, Amount FROM Orders", c))
{
    da.Fill(dtOrders);
}
dgvOrders.DataSource = dtOrders;

DataTable dtStock = new DataTable();
using (OleDbConnection c = new OleDbConnection(inventoryConnStr))
using (OleDbDataAdapter da = new OleDbDataAdapter(
    "SELECT Sku, [Name], Qty FROM Stock", c))
{
    da.Fill(dtStock);
}
dgvStock.DataSource = dtStock;
VB.NET
Imports System.Data

Dim dtOrders As New DataTable()
Using c As New OleDbConnection(ordersConnStr)
    Using da As New OleDbDataAdapter(
        "SELECT Id, CustomerName, Amount FROM Orders", c)
        da.Fill(dtOrders)
    End Using
End Using
dgvOrders.DataSource = dtOrders

Dim dtStock As New DataTable()
Using c As New OleDbConnection(inventoryConnStr)
    Using da As New OleDbDataAdapter(
        "SELECT Sku, [Name], Qty FROM Stock", c)
        da.Fill(dtStock)
    End Using
End Using
dgvStock.DataSource = dtStock

三个及以上库文件

模式相同:再增加路径与连接串即可。建议用小字典或配置(INI/JSON)保存「逻辑名 → 文件路径」,运行时拼出连接串,避免在代码里散落十多条硬编码路径。读写 INI 见 INI 与 INF

C#
string BuildAccessConn(string fileName)
{
    string path = Path.Combine(Application.StartupPath, "Data", fileName);
    return "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + path + ";";
}

// 使用:BuildAccessConn("orders.mdb") / BuildAccessConn("inventory.mdb") / BuildAccessConn("logs.mdb")
VB.NET
Function BuildAccessConn(fileName As String) As String
    Dim path As String = Path.Combine(Application.StartupPath, "Data", fileName)
    Return "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & path & ";"
End Function

' 使用:BuildAccessConn("orders.mdb") / BuildAccessConn("inventory.mdb")

注意事项

主题 说明
一文件一连接 每个库文件使用独立的连接串与 OleDbConnection;短开短关或按需长期持有,但不要混用。
跨库事务 两个 Access 文件之间没有自动分布式事务。需要「两边都成功」时自行做补偿(先写可撤销侧等)。
跨库 JOIN 普通 SQL 不能直接 JOIN 两个物理 .mdb。应分两次查询,或把表合并进同一库,或使用 Access 链接表(进阶,本页不展开)。
文件锁 每个 .mdb 仍有 Jet 锁文件(如 .ldb)。多进程写同一文件会冲突;多文件可降低互相阻塞,但不能消除单文件锁。
位数与引擎 多个库文件共用同一进程的 Jet/ACE。Jet 仅 32 位;全体库文件路径必须真实存在且进程有读写权限。
SQL 注入 用户输入一律参数化(?),不要拼接进 SQL。

扩展:异种库(SQLite + Access)

若还需要在同一项目里同时用 SQLite 与 Access,那是异种提供程序叠加:除 Access 的 OleDb 外,还要按 数据库 · SQLite 引用 System.Data.SQLite,并保证进程位数与 Jet/ACE、SQLite.Interop 一致。连接与查询方式与上文相同——「一库一连接」——只是连接类型分别是 OleDbConnectionSQLiteConnection。本手册将多 Access 库文件作为多数据源主讲;异种混用按各库专页组合即可。

相关阅读