c#使用FreeSql生產(chǎn)環(huán)境時自動升級備份數(shù)據(jù)庫
項目場景:
使用FreeSql,包含所有的ORM數(shù)據(jù)庫,都會存在這樣的問題。在codefirst模式下,根據(jù)代碼自動更新數(shù)據(jù)庫,都建議不要在生產(chǎn)環(huán)境使用。為什么呢?
其實不建議使用,主要是根據(jù)代碼自動生成數(shù)據(jù)時,極有可能會造成數(shù)據(jù)的丟失,比如修改字段類型,自動更新的結(jié)果可能并不是自己想的。
但是有一些使用場景是需要在生產(chǎn)環(huán)境自動升級的,比如
我們有一個CS客戶端的產(chǎn)品,客戶本地離線使用,客戶本地部署,數(shù)據(jù)庫也是本地數(shù)據(jù)庫,版本從1000,迭代到了1100,中間發(fā)布了100個版本。這中間可能有多次數(shù)據(jù)庫更改。我們的客戶也可能遍布全國各地,版本也都不相同。客戶如果沒有新的需求,可能會一直使用當(dāng)前舊版本,只有在有新的需求,或者想使用新的功能時,才會升級版本。所以升級的時間也是不確定的,升級要求客戶安裝新版軟件,運行后自動升級。
那就真的不能在生產(chǎn)環(huán)境使用呢?
解決方案:
概要描述:
解決的思路其實就是自動升級,但是在判斷需要升級時,才自動升級,同時升級前先備份數(shù)據(jù)庫。
具體流程
程序內(nèi)每次有數(shù)據(jù)庫變更,發(fā)布版本時,修改程序內(nèi)對應(yīng)版本。比如最開始是1000,最新是1100
在數(shù)據(jù)庫增加SysConfig表,字段包含DbVer表示當(dāng)前數(shù)據(jù)庫版本號
在數(shù)據(jù)庫增加DbLog表,記錄數(shù)據(jù)庫升級日志,此項可選
在首次安裝時,檢查數(shù)據(jù)庫文件不存在,表示首次安裝,首次安裝時創(chuàng)建SysConfig表和DbLog表,同時更新SysConfig表DbVer為程序中記錄版本號。增加DbLog表日志
以后再次運行時,先獲取SysConfig表DbVer,判斷與程序中是否一致,
如果數(shù)據(jù)庫比程序中大,說明運行低版本的程序,根據(jù)情況可以禁止運行。也可以不同步數(shù)據(jù)庫,繼續(xù)運行,根據(jù)實際情況決定。如果對程序和數(shù)據(jù)庫一致性要求比較高,可以禁止運行。
如果數(shù)據(jù)庫比程序小,說明數(shù)據(jù)庫需要升級,此時先備份現(xiàn)有數(shù)據(jù)庫,然后執(zhí)行同步數(shù)據(jù)庫。
詳細(xì)說明:
直接上代碼,比啥都清楚
program.cs文件代碼
using Bonn.Helper; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Windows.Forms; using FreeSql.DataAnnotations; using WindowsClient.Model; using System.Reflection; namespace WindowsClient { static class Program { /// <summary> /// 客戶數(shù)據(jù)庫路徑 /// </summary> private static string CustDbPath = Application.StartupPath + $"\\數(shù)據(jù)庫\\cust.db"; /// <summary> /// 數(shù)據(jù)庫ORM /// </summary> public static IFreeSql fsql; /// <summary> /// 服務(wù)器數(shù)據(jù)庫版本 /// </summary> private static int ServerDbVer = 1000; /// <summary> /// 應(yīng)用程序的主入口點。 /// </summary> [STAThread] static void Main() { try { //數(shù)據(jù)庫是否存在,用于插入初始數(shù)據(jù),必須在freesql實例化前判斷,因為實例化時會自動創(chuàng)建數(shù)據(jù)庫 var custDbPathExists = File.Exists(CustDbPath); //deebug自動同步實體結(jié)構(gòu)到數(shù)據(jù)庫,release手動同步 bool syncDbStructure = false; #if DEBUG syncDbStructure = true; #endif fsql = new FreeSql.FreeSqlBuilder() .UseConnectionString(FreeSql.DataType.Sqlite, $@"Data Source={CustDbPath}; Pooling=true;Min Pool Size=1") .UseAutoSyncStructure(syncDbStructure) //deebug自動同步實體結(jié)構(gòu)到數(shù)據(jù)庫,release手動同步 .UseMonitorCommand(cmd => Console.WriteLine($"線程:{cmd.CommandText}\r\n")) .Build(); //請務(wù)必定義成 Singleton 單例模式 if(syncDbStructure) { //主要用于開發(fā)模式下,讓數(shù)據(jù)庫修改快速生效,不加此句時,只有在用到表時才會同步 fsql.CodeFirst.SyncStructure(GetTypesByTableAttribute()); } if (custDbPathExists == false) { //數(shù)據(jù)庫文件不存在,表示是首次安裝 fsql.CodeFirst.SyncStructure(GetTypesByTableAttribute()); var sysConfig = new SysConfig(); sysConfig.DbVer = ServerDbVer; var dbResult = fsql.Insert(sysConfig).ExecuteAffrows(); if (dbResult <= 0) throw new Exception("初始數(shù)據(jù)庫失敗。"); var row = new DbLog(); row.DbVer = ServerDbVer; fsql.Insert(row).ExecuteAffrows(); } int localDbVer = fsql.Select<SysConfig>().First().DbVer; if (localDbVer != ServerDbVer) { //數(shù)據(jù)庫版本不一樣,需要升級 //備份數(shù)據(jù)庫 File.Copy(CustDbPath, Application.StartupPath + $"\\數(shù)據(jù)庫\\cust{DateTime.Now:yyyyMMddHHmmss}.db"); //升級數(shù)據(jù)庫 fsql.CodeFirst.SyncStructure(GetTypesByTableAttribute()); var row = new DbLog(); row.DbVer = ServerDbVer; fsql.Insert(row).ExecuteAffrows(); } Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new FrmMain()); } catch (Exception e) { MessageBox.Show(e.ToString(), "出錯啦", MessageBoxButtons.OK, MessageBoxIcon.Error); } } public static Type[] GetTypesByTableAttribute() { List<Type> tableAssembies = new List<Type>(); foreach (Type type in Assembly.GetAssembly(typeof(IEntity)).GetExportedTypes()) { foreach (Attribute attribute in type.GetCustomAttributes()) { if (attribute is TableAttribute tableAttribute) { if (tableAttribute.DisableSyncStructure == false) { tableAssembies.Add(type); } } } }; return tableAssembies.ToArray(); } } }
SysConfig.cs
using FreeSql.DataAnnotations; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WindowsClient.Model { /// <summary> /// /// </summary> [Table(Name = "sys_config")] public class SysConfig : IEntity { /// <summary> /// 主鍵 /// </summary> [Column(Name = "id", IsIdentity = true, IsPrimary = true)] public int Id { get; set; } /// <summary> /// 主鍵 /// </summary> [Column(Name = "dbVer")] public int DbVer { get; set; } /// <summary> /// 創(chuàng)建時間 /// </summary> [Column(ServerTime = DateTimeKind.Local, CanUpdate = false)] public DateTime CreateTime { get; set; } /// <summary> /// 修改時間 /// </summary> [Column(ServerTime = DateTimeKind.Local, CanUpdate = true)] public DateTime UpdateTime { get; set; } } }
DbLog.cs
using FreeSql.DataAnnotations; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WindowsClient.Model { /// <summary> /// /// </summary> [Table(Name = "db_log")] public class DbLog : IEntity { /// <summary> /// 主鍵 /// </summary> [Column(Name = "id", IsIdentity = true, IsPrimary = true)] public int Id { get; set; } /// <summary> /// 主鍵 /// </summary> [Column(Name = "dbVer")] public int DbVer { get; set; } /// <summary> /// 創(chuàng)建時間 /// </summary> [Column(ServerTime = DateTimeKind.Local, CanUpdate = false)] public DateTime CreateTime { get; set; } /// <summary> /// 修改時間 /// </summary> [Column(ServerTime = DateTimeKind.Local, CanUpdate = true)] public DateTime UpdateTime { get; set; } } }
總結(jié):
以前是手寫的SQL語句,現(xiàn)在用FreeSql確實方便多了。
以上就是c#使用FreeSql生產(chǎn)環(huán)境自動升級備份數(shù)據(jù)庫的詳細(xì)內(nèi)容,更多關(guān)于c# 用FreeSql自動升級備份數(shù)據(jù)庫的資料請關(guān)注腳本之家其它相關(guān)文章!
- C#連接SQL數(shù)據(jù)庫和查詢數(shù)據(jù)功能的操作技巧
- C# TreeView從數(shù)據(jù)庫綁定數(shù)據(jù)的示例
- C#從數(shù)據(jù)庫讀取圖片并保存的兩種方法
- C# 創(chuàng)建MDB數(shù)據(jù)庫、并存放表格數(shù)據(jù)的案例
- C#使用SqlServer作為日志數(shù)據(jù)庫的設(shè)計與實現(xiàn)
- C#窗體-數(shù)據(jù)庫連接及登錄功能的實現(xiàn)案例
- C#連接SQL Server數(shù)據(jù)庫的實例講解
- C#連接Oracle數(shù)據(jù)庫字符串(引入DLL)的方式
- C# Ado.net實現(xiàn)讀取SQLServer數(shù)據(jù)庫存儲過程列表及參數(shù)信息示例
相關(guān)文章
c# Rank屬性與GetUpperBound方法的深入分析
本篇文章是對c#中的Rank屬性與GetUpperBound方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06快速了解如何在.NETCORE中使用Generic-Host建立主機(jī)
這篇文章主要介紹了如何在.NETCORE中使用Generic-Host建立主機(jī),文中代碼非常詳細(xì),可供大家參考,感興趣的朋友不妨閱讀完2020-05-05