C#.NET ORM 如何访问 Access 数据库 [FreeSql]

最近很多 .net QQ 群无故被封停,特别是 wpf 群几乎全军覆没。依乐祝的 .net6交流群,晓晨的 .net跨平台交流群,导致很多码友流离失所无家可归,借此机会使用一次召唤术,有需要的请加群:560611514【.NET C#爱好者】,6406277【C#/.Net Core社区】,822074314【DotNet开发交流群】

💻 前言

看到标题点进来,也许有人问,为什么不用 mysql,为什么不用 sqlite,为什么不这样那样。

其实有时候情非得已,被迫使用不由得自己选择,没有谁天天做新项目,新项目当然不会选 Access 数据库,复杂的业务群体对方发送过来的文件是 Access 也没得选,难道可以要求对方公司换数据库?

Microsoft Office Access是由微软发布的关系数据库管理系统。它结合了 MicrosoftJet Database Engine 和 图形用户界面两项特点,是 Microsoft Office 的系统程序之一。

Microsoft Office Access是微软把数据库引擎的图形用户界面和软件开发工具结合在一起的一个数据库管理系统。它是微软OFFICE的一个成员, 在包括专业版和更高版本的office版本里面被单独出售。2018年9月25日,最新的微软Office Access 2019在微软Office 2019里发布。

MS ACCESS以它自己的格式将数据存储在基于Access Jet的数据库引擎里。它还可以直接导入或者链接数据(这些数据存储在其他应用程序和数据库)。


🌳 C#.NET 访问 Access 数据库

从 .NETframework 1.0 到现今的 dotnet-7.0,访问 Access 数据库都只能用 oledb 方式,微软历史访问数据库的方式有许多种(ado、odbc、oledb、ado.net),oledb 是其中的一种。

连接字符串常见的有两种:

  • Provider=Microsoft.Jet.OleDb.4.0;Data Source=d:/accdb/2003.mdb
  • Provider=Microsoft.ACE.OLEDB.12.0;Data Source=d:/accdb/2007.accdb

Access 支持 SQL 语句,使用起来和普通关系型数据库差不多,由于不想在代码中写 SQL,为了让 crud 操作起来更加便利,决定引入 C#.NET ORM Freesql,因为他支持 .NETFramework 4.0 及以后的所有 dotnet 版本,适应范围更广。


🦄 FreeSql 介绍

.NET ORM Object Relational Mapping 是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。

FreeSql .NET ORM 支持 .NetFramework4.0+、.NetCore、Xamarin、MAUI、Blazor、以及还有说不出来的运行平台,因为代码绿色无依赖,支持新平台非常简单。目前单元测试数量:8500+,Nuget下载数量:1M+。使用最宽松的开源协议 MIT https://github.com/dotnetcore/FreeSql ,可以商用,文档齐全,甚至拿去卖钱也可以。

FreeSql 主要优势在于易用性上,基本是开箱即用,在不同数据库之间切换兼容性比较好,整体的功能特性如下:

  • 支持 CodeFirst 对比结构变化迁移、DbFirst 从数据库生成实体类;
  • 支持 丰富的表达式函数,独特的自定义解析;
  • 支持 批量添加、批量更新、BulkCopy、导航属性,贪婪加载、延时加载、级联保存、级联删除;
  • 支持 读写分离、分表分库,租户设计,分布式事务;
  • 支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite/Firebird/达梦/神通/人大金仓/翰高/Clickhouse/MsAccess Ado.net 实现包,以及 Odbc 的专门实现包;

8000+个单元测试作为基调,支持10多数数据库,我们提供了通用Odbc理论上支持所有数据库,目前已知有群友使用 FreeSql 操作华为高斯、mycat、tidb 等数据库。安装时只需要选择对应的数据库实现包:

dotnet add packages FreeSql.Provider.MsAccess
public class DB
{
    static Lazy<IFreeSql> accessLazy = new Lazy<IFreeSql>(() => new FreeSql.FreeSqlBuilder()
        .UseConnectionString(FreeSql.DataType.MsAccess, "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=d:/accdb/2007.accdb")
        //.UseAutoSyncStructure(true) 自动建表,适合新项目
        .UseNoneCommandParameter(true)
        .UseMonitorCommand(cmd => Trace.WriteLine(cmd.CommandText))
        .Build());
    public static IFreeSql access => accessLazy.Value;
}

定义 DB.cs 类之后就可以快乐的 CRUD 了。FreeSql 提供多种 CRUD 使用习惯,请根据实际情况选择团队合适的一种:

  • 要么 FreeSql,原始用法;
  • 要么 FreeSql.Repository,仓储 + 工作单元习惯;
  • 要么 FreeSql.DbContext,很像 EFCore 的使用习惯,兼容 EFCore 99% 的实体注解;
  • 要么 FreeSql.BaseEntity,充血模式;
  • 要么 直接像 dapper 那样使用 SqlConnection 扩展方法;

⚡ CRUD 模式一:原始用法 API

DB.access.Select<T>(); //查询
DB.access.Insert<T>(); //插入
DB.access.Update<T>(); //更新
DB.access.Delete<T>(); //删除
DB.access.InsertOrUpdate<T>()// 插入或更新
DB.access.Transaction(..); //事务

DB.access.CodeFirst; //CodeFirst 对象
DB.access.DbFirst; //DbFirst 对象
DB.access.Ado; //Ado 对象
DB.access.Aop; //Aop 对象
DB.access.GlobalFilter; //全局过滤器对象


var blogs = DB.access.Select<Blog>()
    .Where(b => b.Rating > 3)
    .OrderBy(b => b.Url)
    .Page(2, 10)
    .ToList();

var blog = new Blog { Url = "http://sample.com" };
blog.BlogId = (int)DB.access.Insert(blog).ExecuteIdentity();

DB.access.Update<Blog>()
    .Set(b => b.Url, "http://sample2222.com")
    .Where(b => b.Url == "http://sample.com")
    .ExecuteAffrows();

DB.access.Delete<Blog>()
    .Where(b => b.Url == "http://sample.com")
    .ExecuteAffrows();

// 等等等。。级联保存、级联查询、导航属性。。。

⛳ CRUD 模式二:仓储 + 工作单元

FreeSql.Repository 作为扩展,实现了通用仓储层功能。与其他规范标准一样,仓储层也有相应的规范定义。FreeSql.Repository 参考 abp vnext 接口,定义和实现基础的仓储层(CURD),算比较通用的方法。

  • Select/Attach 快照对象,Update 只更新变化的字段;
  • Insert 插入数据,适配各数据库优化执行 ExecuteAffrows/ExecuteIdentity/ExecuteInserted;
  • InsertOrUpdate 插入或更新;
  • SaveMany 方法快速保存导航对象(一对多、多对多);
  • 工作单元管理事务
//Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IFreeSql>(DB.access);
    services.AddScoped<UnitOfWorkManager>();
    services.AddFreeRepository(null, typeof(Startup).Assembly);
   //批量注入 Service
}


public class SongService
{
    readonly IBaseRepository<Song> _repoSong;
    readonly IBaseRepository<Detail> _repoDetail;

    public SongService(IBaseRepository<Song> repoSong, IBaseRepository<Detail> repoDetail)
    {
        _repoSong = repoSong;
        _repoDetail = repoDetail;
    }

    [Transactional]
    public virtual void Test1()
    {
        //这里 _repoSong、_repoDetail 所有操作都是一个工作单元
        this.Test2();
    }

    [Transactional(Propagation = Propagation.Nested)]
    public virtual void Test2() //嵌套事务
    {
        //这里 _repoSong、_repoDetail 所有操作都是一个工作单元
    }
}
属性返回值说明
EntityTypeType仓储正在操作的实体类型,注意它不一定是 TEntity
UnitOfWorkIUnitOfWork正在使用的工作单元
OrmIFreeSql正在使用的 Orm
DbContextOptionsDbContextOptions正在使用的 DbContext 设置,修改设置不影响其他
DataFilterIDataFilter\<TEntity\>仓储过滤器,本对象内生效
UpdateDiyIUpdate\<TEntity\>准备更新数据,与仓储同事务
SelectISelect\<TEntity\>准备查询数据
方法返回值参数说明
AsTypevoidType改变仓储正在操作的实体类型
GetTEntityTKey根据主键,查询数据
FindTEntityTKey根据主键,查询数据
DeleteintTKey根据主键删除数据
DeleteintLambda根据 lambda 条件删除数据
DeleteintTEntity删除数据
DeleteintIEnumerable\<TEntity\>批量删除数据
DeleteCascadeByDatabaseList\<object\>Lambda根据导航属性递归数据库删除数据
Insert-TEntity插入数据,若实体有自增列,插入后的自增值会填充到实体中
Insert-IEnumerable\<TEntity\>批量插入数据
Update-TEntity更新数据
Update-IEnumerable\<TEntity\>批量更新数据
InsertOrUpdate-TEntity插入或更新数据
FlushState-清除状态管理数据
Attach-TEntity附加实体到状态管理,可用于不查询就更新或删除
Attach-IEnumerable\<TEntity\>批量附加实体到状态管理
AttachOnlyPrimary-TEntity只附加实体的主键数据到状态管理
SaveMany-TEntity, string保存实体的指定 ManyToMany/OneToMany 导航属性(完整对比)
BeginEdit-List\<TEntity\>准备编辑一个 List 实体
EndEditint完成编辑数据,进行保存动作
状态管理,可实现 Update 只更新变化的字段(不更新所有字段),灵活使用 Attach 和 Update 用起来非常舒服。

⚡ CRUD 模式三:DbContext

FreeSql.DbContext 实现类似 EFCore 使用习惯,跟踪对象状态,最终通过 SaveChanges 方法提交事务。

FreeSql 可自动识别 EFCore 实体特性 Key/Required/NotMapped/MaxLength/StringLength/DatabaseGenerated/Table/Column。

  • Select/Attach 快照对象,Update 只更新变化的字段;
  • Add/AddRange 插入数据,适配各数据库优化执行 ExecuteAffrows/ExecuteIdentity/ExecuteInserted;
  • AddOrUpdate 插入或更新;
  • SaveMany 方法快速保存导航对象(一对多、多对多);
using (var ctx = DB.oracle.CreateDbContext()) {
  //var db1 = ctx.Set<Song>();
  //var db2 = ctx.Set<Tag>();

  var item = new Song { };
  ctx.Add(item);
  ctx.SaveChanges();
}

// 或者

public class SongContext : DbContext {

  public DbSet<Song> Songs { get; set; }
  public DbSet<Tag> Tags { get; set; }

  protected override void OnConfiguring(DbContextOptionsBuilder builder) {
    builder.UseFreeSql(DB.oracle);
  }
  
  //每个 DbContext 只触发一次
  protected override void OnModelCreating(ICodeFirst codefirst)
  {
    codefirst.Entity<Song>(eb =>
    {
      eb.ToTable("tb_song");
      eb.Ignore(a => a.Field1);
      eb.Property(a => a.Title).HasColumnType("varchar(50)").IsRequired();
      eb.Property(a => a.Url).HasMaxLength(100);
    }
  }
}

提示:FreeSql 兼容 EFCore 99% 的实体特性


🌴 CRUD 模式四:BaseEntity

BaseEntity 是一种极简单的 CodeFirst 开发方式,特别对单表或多表CRUD,利用继承节省了每个实体类的重复属性(创建时间、ID等字段),软件删除等功能,进行 crud 操作时不必时常考虑仓储的使用;

dotnet add package FreeSql.Extensions.BaseEntity
public class UserGroup : BaseEntity<UserGroup, int>
{
    public string GroupName { get; set; }
}

//添加
var item = new UserGroup { GroupName = "组一" };
item.Insert();

//更新
item.GroupName = "组二";
item.Update();

//添加或更新
item.Save();

//软删除
item.Delete();

//恢复软删除
item.Restore();

//根据主键获取对象
var item = UserGroup.Find(1);

//查询数据
var items = UserGroup.Where(a => a.Id > 10).ToList();

📃 CRUD 模式五:SqlConnection 扩展方法(类似 Dapper)

提供了类似 Dapper 的使用方法,FreeSql 增加了 IDbConnection/IDbTransaction 对象的扩展方法 Select/Insert/Update/Delete 实现 CRUD。

using FreeSql;

using (var conn = new SqlConnection(...))
{
  conn.Select<T>().Where(...).ToList();

  conn.Insert(new T {}).ExecuteAffrows();
  conn.Update().SetSource(new T {}).ExecuteAffrows();
  conn.InsertOrUpdate().SetSource(new T {}).ExecuteAffrows();

  conn.Delete<T>().Where(...).ExecuteAffrows();
}
  • 每个 SqlConnection GetFreeSql() 返回的 IFreeSql 实例相同;
  • 可以对 fsql 设置 Aop 事件,比如监视 SQL;
  • IFreeSql 自身的成员 IDbFirst、Transaction 不可用;

利用本功能可以快速将 FreeSql 使用到项目中,只需要处理好实体类的特性。


🌈 结束语

作者是什么人?

作者是一个入行 18年的老批,他目前写的.net 开源项目有:

开源项目描述开源地址开源协议
FreeIM聊天系统架构https://github.com/2881099/Fr...MIT
FreeRedisRedis SDKhttps://github.com/2881099/Fr...MIT
csredis https://github.com/2881099/cs...MIT
FightLandlord斗DI主网络版https://github.com/2881099/Fi...学习用途
FreeScheduler定时任务https://github.com/2881099/Fr...MIT
IdleBus空闲容器https://github.com/2881099/Id...MIT
FreeSqlORMhttps://github.com/dotnetcore...MIT
FreeSql.Cloud分布式tcc/sagahttps://github.com/2881099/Fr...MIT
FreeSql.AdminLTE低代码后台生成https://github.com/2881099/Fr...MIT
FreeSql.DynamicProxy动态代理https://github.com/2881099/Fr...学习用途

需要的请拿走,这些都是最近几年的开源作品,以前更早写的就不发了。

FreeSql .NET ORM 支持 .NetFramework4.0+、.NetCore、Xamarin、MAUI、Blazor、以及还有说不出来的运行平台,因为代码绿色无依赖,支持新平台非常简单。目前单元测试数量:8500+,Nuget下载数量:1M+。QQ群:4336577(已满)、8578575(在线)、52508226(在线)

  • 支持 CodeFirst 模式;
  • 支持 DbFirst 模式,支持从数据库导入实体类,或使用实体类生成工具生成实体类;
  • 支持 丰富的表达式函数,以及灵活的自定义解析;
  • 支持 导航属性一对多、多对多贪婪加载,延时加载,级联保存,级联删除;
  • 支持 读写分离、分表分库、过滤器、乐观锁、悲观锁、分布式事务、多租户(按字段/表/库);
  • 支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite/Firebird/达梦/人大金仓/神舟通用/南大通用/翰高/华为高斯/ClickHouse/Access 等数据库;

FreeSql 使用最宽松的开源协议 MIT https://github.com/dotnetcore/FreeSql ,可以商用,文档齐全,甚至拿去卖钱也可以。

8500+个单元测试作为基调,支持10多数数据库,我们提供了通用Odbc理论上支持所有数据库,目前已知有群友使用 FreeSql 操作华为高斯、mycat、tidb 等数据库。安装时只需要选择对应的数据库实现包。

轻量化解释:了解 FreeRedis、FreeSql、csredis 的人都知道,我们发布的开源项目是绿色著称,零依赖发布后只有一个DLL,不会造成使用者项目依赖冲突,支持 .NET 4.0 堪称屎山项目的救星。现在还有很多.NET FX4.0 的项目,这些项目因历史遗留原因或硬件限制,不能更换 .NET Core 版本。因此这些项目很难使用到现有的开源库,不能使用可靠的开源库,那么很多时候都要自行实现,在堆积代码的同时,项目也有可能越来越乱,代码越来越渣,项目逐渐变得不稳定。

3 声望
1 粉丝
0 条评论
推荐阅读
必看!.NET 7 在网络领域的四大更新
最新的 .NET 7 现已发布,我们想介绍一下其在网络领域所做的一些有趣的更改和添加。这篇文章我们将讨论 .NET 7 在 HTTP 空间、新 QUIC API、网络安全和 WebSockets 方面的变化。

微软技术栈1阅读 439

封面图
(持续更新,已更新至2022年11月26日)C语言经典题集合
(持续更新,最新时间2022年11月26日)1. 三个数由小到大排序输入任意3个整数,编程实现对这3个整数进行由小到大排序井将排序后的结果显示在屏幕上 {代码...} 2. a²+b²要求输入整数a和 b, 若a²+b²的结果大与100, ...

瞿小凯阅读 1.4k评论 2

封面图
node.js基于 cmake-js 进行插件开发实战
以前工作在node.js环境下,做微服务产品; 三年前转回到C++环境,已经有一些代码积攒。我将以往基于node.js与C++的相关项目结合起来(C++代码以addon插件嵌入),实现了一个微服务快速(rest api service)开发框...

zhoutk阅读 812

C#基础巩固与进阶(定时语音播报+PDF水印+分片上传+EF6框架)
b站视频:2022年C#进阶教程-C#应该学到什么程度(针对编程思维)前提UI框架:WinForm(基于.net framework 4.6.1)、MaterialSkin.2(v2.3.0.0) {代码...} ps:如果你想使用wpf到达类似界面效果可以参考。[链接]章...

程序员ken2阅读 381

比特熊故事汇2.0 | 矛盾个性是促成创意不竭的正反合
2023年开年故事汇,我们请来一位“熟悉的新朋友”,他乐观、谨慎、敢于尝试、富有想象力,擅长Azure、AI、C#、产品设计。他是拥有10年+经验的微软MVP,也是有点社恐却谈笑风生的开发人。本期比特熊故事汇主人公——王...

微软技术栈阅读 771

封面图
使用 .NET 7、Blazor 和 .NET MAUI 构建你自己的 Podcast App
.NET Podcast App 首次在 .NET Conf 2021上推出,最近进行了更新以在 .NET Conf 2022 keynote 中突出显示 .NET 7 中的新功能。该 Podcast App 已准备好使用展示 .NET,ASP.NET Core,Blazor,.NET MAUI,Azure Co...

微软技术栈阅读 686

封面图
官方盘点 .NET 7 新功能
.NET 7 为C# 11/F# 7、.NET MAUI、ASP.NET Core/Blazor、Web API、WinForms、WPF 等应用程序带来了更高的性能和新功能。使用 .NET 7,您还可以轻松地将 .NET 7 项目容器化,在 GitHub 操作中设置 CI/CD 工作流,...

微软技术栈阅读 614

封面图
3 声望
1 粉丝
宣传栏