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資料庫中文顯示亂碼問題
//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 = "//sample.com" };
blog.BlogId = (int)DB.Oracle.Insert(blog).ExecuteIdentity();
DB.Oracle.Update<Blog>()
.Set(b => b.Url, "//sample2222.com")
.Where(b => b.Url == "//sample.com")
.ExecuteAffrows();
DB.Oracle.Delete<Blog>()
.Where(b => b.Url == "//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 //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資料庫中文顯示亂碼問題
//blog.csdn.net/guhun_shmily/article/details/83064225