? 前言
关于 Oracle US7ASCII 中文乱码的问题,Ado.Net 和 Odbc 无法解决。包括最新的.Net Core、.NET6、.NET7 都无法解决这个问题。
FreeSql 对 Oracle 支持非常友好,是 c#.net ORM 不二之选,提供了 Ado.net 实现包 FreeSql.Provider.Oracle,Odbc 实现包 FreeSql.Provider.Odbc,Oledb 实现包 FreeSql.Provider.OracleOledb,他们都支持 .NETCore2.1+、.NET4.0+ 等最新或较低的 .NETFramework 版本。
FreeSql 访问 Oracle 只需要引用 FreeSql.Provider.Oracle/FreeSql.Provider.Odbc/FreeSql.Provider.OracleOledb 任意一个包即可。
若想以 Ado.net 驱动访问数据库,请安装:
dotnet add package FreeSql.Provider.Oracle
若想以 ODBC 驱动访问数据库,请安装:
dotnet add package FreeSql.Provider.Odbc
若想以 Oledb 驱动访问数据库,请安装:
dotnet add package FreeSql.Provider.OracleOledb
? 解决办法
安装 FreeSql.Provider.OracleOledb 使用 Oledb 驱动解决读取使用 US7ASCII 的 Oracle 数据库中文显示乱码问题。
有关 US7ASCII Oracle 参考了其他解决方法:
C#处理读取使用US7ASCII的oracle数据库中文显示乱码问题 https://blog.csdn.net/guhun_shmily/article/details/83064225
public class DB { static Lazy<IFreeSql> oracleLazy = new Lazy<IFreeSql>(() => new FreeSql.FreeSqlBuilder() .UseConnectionString(FreeSql.DataType.Oracle, "Provider=OraOLEDB.Oracle;user id=9user;password=123456;data source=//127.0.0.1:1521/XE;Pooling=true;Max Pool Size=2") //.UseConnectionString(FreeSql.DataType.OdbcOracle, "...") //ODBC 特定类型 .UseAutoSyncStructure(true) .UseNameConvert(FreeSql.Internal.NameConvertType.ToUpper) .UseNoneCommandParameter(true) .UseMonitorCommand(cmd => Trace.WriteLine(cmd.CommandText)) .Build()); public static IFreeSql oracle => oracleLazy.Value; }
定义 DB.cs 类之后就可以快乐的 CRUD 了。FreeSql 提供多种 CRUD 使用习惯,请根据实际情况选择团队合适的一种:
- 要么 FreeSql,原始用法;
- 要么 FreeSql.Repository,仓储+工作单元习惯;
- 要么 FreeSql.DbContext,很像 EFCore 的使用习惯;
- 要么 FreeSql.BaseEntity,充血模式;
- 要么 直接像 dapper 那样使用 OracleConnection 扩展方法;
? CRUD 模式一:原始用法 API
DB.oracle.Select<T>(); //查询 DB.oracle.Insert<T>(); //插入 DB.oracle.Update<T>(); //更新 DB.oracle.Delete<T>(); //删除 DB.oracle.InsertOrUpdate<T>()// 插入或更新 DB.oracle.Transaction(..); //事务 DB.oracle.CodeFirst; //CodeFirst 对象 DB.oracle.DbFirst; //DbFirst 对象 DB.oracle.Ado; //Ado 对象 DB.oracle.Aop; //Aop 对象 DB.oracle.GlobalFilter; //全局过滤器对象 var blogs = DB.Oracle.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.Oracle.Insert(blog).ExecuteIdentity(); DB.Oracle.Update<Blog>() .Set(b => b.Url, "http://sample2222.com") .Where(b => b.Url == "http://sample.com") .ExecuteAffrows(); DB.Oracle.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 方法快速保存导航对象(一对多、多对多);
- 工作单元管理事务
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 所有操作都是一个工作单元 } }
属性 | 返回值 | 说明 |
---|---|---|
EntityType | Type | 仓储正在操作的实体类型,注意它不一定是 TEntity |
UnitOfWork | IUnitOfWork | 正在使用的工作单元 |
Orm | IFreeSql | 正在使用的 Orm |
DbContextOptions | DbContextOptions | 正在使用的 DbContext 设置,修改设置不影响其他 |
DataFilter | IDataFilter<TEntity> | 仓储过滤器,本对象内生效 |
UpdateDiy | IUpdate<TEntity> | 准备更新数据,与仓储同事务 |
Select | ISelect<TEntity> | 准备查询数据 |
方法 | 返回值 | 参数 | 说明 |
---|---|---|---|
AsType | void | Type | 改变仓储正在操作的实体类型 |
Get | TEntity | TKey | 根据主键,查询数据 |
Find | TEntity | TKey | 根据主键,查询数据 |
Delete | int | TKey | 根据主键删除数据 |
Delete | int | Lambda | 根据 lambda 条件删除数据 |
Delete | int | TEntity | 删除数据 |
Delete | int | IEnumerable<TEntity> | 批量删除数据 |
DeleteCascadeByDatabase | List<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 实体 |
EndEdit | int | 无 | 完成编辑数据,进行保存动作 |
状态管理,可实现 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(); } // 或者 ```csharp 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); } } }
? 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 模式五:OracleConnection 扩展方法(类似 Dapper)
提供了类似 Dapper 的使用方法,FreeSql 增加了 IDbConnection/IDbTransaction 对象的扩展方法 Select/Insert/Update/Delete 实现 CRUD。
using FreeSql; using (var conn = new OracleConnection(...)) { 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(); }
- 每个 OracleConnection GetFreeSql() 返回的 IFreeSql 实例相同;
- 可以对 fsql 设置 Aop 事件,比如监视 SQL;
- IFreeSql 自身的成员 IDbFirst、Transaction 不可用;
利用本功能可以快速将 FreeSql 使用到项目中,只需要处理好实体类的特性。
提示:FreeSql 兼容 EFCore 99% 的实体特性
? 功能特性
- 支持 CodeFirst 模式;
- 支持 DbFirst 模式,支持从数据库导入实体类,或使用实体类生成工具生成实体类;
- 支持 丰富的表达式函数,以及灵活的自定义解析;
- 支持 导航属性一对多、多对多贪婪加载,延时加载,级联保存,级联删除;
- 支持 读写分离、分表分库、过滤器、乐观锁、悲观锁、分布式事务、多租户(按字段/表/库);
- 支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite/Firebird/达梦/人大金仓/神舟通用/南大通用/翰高/华为高斯/ClickHouse/Access 等数据库;
FreeSql .NET ORM 支持 .NetFramework4.0+、.NetCore、Xamarin、MAUI、Blazor、以及还有说不出来的运行平台,因为代码绿色无依赖,支持新平台非常简单。目前单元测试数量:8500+,Nuget下载数量:1M+。QQ群:4336577(已满)、8578575(在线)、52508226(在线)
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 版本。因此这些项目很难使用到现有的开源库,不能使用可靠的开源库,那么很多时候都要自行实现,在堆积代码的同时,项目也有可能越来越乱,代码越来越渣,项目逐渐变得不稳定。
? 结束语
有关 US7ASCII Oracle 参考了其他解决方法:
C#处理读取使用US7ASCII的oracle数据库中文显示乱码问题
https://blog.csdn.net/guhun_shmily/article/details/83064225