C#.NET ORM FreeSql 读取使用 US7ASCII 的 Oracle 数据库中文显示乱码问题


💻 前言

关于 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 = fsql.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)fsql.Insert(blog).ExecuteIdentity();

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

fsql.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();
}

// 或者

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 模式,支持从数据库导入实体类,或使用[实体类生成工具](https://freesql.net/guide/db-first.html)生成实体类;
- 支持 丰富的表达式函数,以及灵活的自定义解析;
- 支持 导航属性一对多、多对多贪婪加载,延时加载,级联保存,级联删除;
- 支持 读写分离、分表分库、过滤器、乐观锁、悲观锁、分布式事务、多租户(按字段/表/库);
- 支持 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](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数据库中文显示乱码问题

相关文章

暂无评论

暂无评论...