c# 使用Entity Framework操作Access数据库
Entity Framework 是 C#开发中最常见的 ORM 工具。默认 Entity Framework 只提供支持 MSSQL 的provider factory
。但是开发者开源贡献了对 SQLite、MySql 以及 Access 等的支持。
JetEntityFrameworkProvider
JetEntityFrameworkProvider 为 Access 数据库文件兼容 Entity Framework 提供了相应的Provider
。在 nuget 中直接搜索 JetEntityFrameworkProvider 即可安装该工具。虽然大多数操作最终是 EntityFramework 完成因此不需要什么变化,而在数据库连接等方面还是有些不同和需要注意的地方。
数据库连接
官方的资源并不多,只提供了一两个简单的操作视频
其中使用的connectionString
为在 App.config 中或 Web.config 中预定义的以供 DbContext 实例化时引用。
<connectionStrings>
<add name="DefaultConnection" connectionString="Provider=Microsoft.ACE.OleDb.12.0;Data Source=你的mdb或accdb文件绝对路径" providerName="JetEntityFrameworkProvider" />
</connectionStrings>
这样你在实例化自定义的DbContext
子类时直接base("name=DefaultConnection")
即可建立数据库连接。
但是我个人不喜欢在配置文件中写死配置,我更希望使用base(existingConnection, contextOwnsConnection)
这种 DbContext 构造模式,所以需要先直接生成一个DbConnection
,这里具体的就是OleDbConnection
而不是SqlConnection
了。
按照下面的方式直接使用DbProviderFactory
创建连接:
var dbConnectionString = "Provider=Microsoft.ACE.OleDb.12.0;Data source=Access文件绝对路径;Persist Security Info=False";
var conn = DbProviderFactories.GetFactory("JetEntityFrameworkProvider").CreateConnection();
conn.ConnectionString = dbConnectionString;
Code First 或 DB First
默认地,JetEntityFrameworkProvider 只支持 code first 模式。即你先写好模型,然后根据模型生成数据库。
但是我的需求是用 EF 读取已存在的 Access 数据库文件,即 DB First 模式,这时使用 EF 读取 Access 数据库文件会报错提示数据表已存在。
通过 code first 模式的测试发现:
JetEntityFrameworkProvider 会创建一个名为__MigrationHistory
的表,字段如下:
MigrationId - text格式
ContextKey - memo格式
Model - OleObject格式
ProductVersion - text格式
MigrationId 值的例子为201612281720088_InitialCreate
ContextKey 应该是自定义的 DbContext 类的 namespace 加类名的格式
Model 是二进制的数据无法查看
ProductVersion 包含了 Entity Framework 的版本号和 JetEntityFrameworkProvider 的版本号
因此我尝试在 EF 连接之前用普通 SQL query 方式插入记录:
var dbConnectionString = "Provider=Microsoft.ACE.OleDb.12.0;Data source=Access文件绝对路径;Persist Security Info=False";
conn = new OleDbConnection(dbConnectionString);
conn.Open();
var exists = conn.GetSchema("Tables", new string[4] { null, null, "__MigrationHistory", "TABLE" }).Rows.Count > 0;
if(!exists)
{
OleDbCommand cmd = new OleDbCommand("CREATE TABLE __MigrationHistory([MigrationId] TEXT, [ContextKey] MEMO, [Model] OleObject, [ProductVersion] TEXT)", conn);
cmd.ExecuteNonQuery();
cmd = new OleDbCommand("INSERT INTO __MigrationHistory(MigrationId, ContextKey, ProductVersion) VALUES('" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + "', '" + typeof(ATOrionContext).Namespace + ".ATOrionContext', '6.1.3-40302')", conn);
cmd.ExecuteNonQuery();
}
执行如上操作后确实能够利用 EF 连接已存在模型对应数据表的 Access 数据库文件了,但是执行查询操作仍然会报错buffer is null
经过 Debug 发现此 buffer 指的就是插入记录的 Model 字段,我们插入时没有提供值,因为它是一个二进制数据,内容生成方式未知。
尝试注释掉插入记录的操作,只添加__MigrationHistory 表,而结果也令人兴奋,可以通过模型验证并且能够使用 EF 进行 DB First 模式的数据开发模式了。
- 原文作者:Touchumind
- 原文链接:https://blog.fedepot.com/post/csharp-entity-framework/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。