💻 前言
關於 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數據庫中文顯示亂碼問題