c#使用FreeSql生產(chǎn)環(huán)境時(shí)自動(dòng)升級(jí)備份數(shù)據(jù)庫
項(xiàng)目場(chǎng)景:
使用FreeSql,包含所有的ORM數(shù)據(jù)庫,都會(huì)存在這樣的問題。在codefirst模式下,根據(jù)代碼自動(dòng)更新數(shù)據(jù)庫,都建議不要在生產(chǎn)環(huán)境使用。為什么呢?
其實(shí)不建議使用,主要是根據(jù)代碼自動(dòng)生成數(shù)據(jù)時(shí),極有可能會(huì)造成數(shù)據(jù)的丟失,比如修改字段類型,自動(dòng)更新的結(jié)果可能并不是自己想的。
但是有一些使用場(chǎng)景是需要在生產(chǎn)環(huán)境自動(dòng)升級(jí)的,比如
我們有一個(gè)CS客戶端的產(chǎn)品,客戶本地離線使用,客戶本地部署,數(shù)據(jù)庫也是本地?cái)?shù)據(jù)庫,版本從1000,迭代到了1100,中間發(fā)布了100個(gè)版本。這中間可能有多次數(shù)據(jù)庫更改。我們的客戶也可能遍布全國各地,版本也都不相同??蛻羧绻麤]有新的需求,可能會(huì)一直使用當(dāng)前舊版本,只有在有新的需求,或者想使用新的功能時(shí),才會(huì)升級(jí)版本。所以升級(jí)的時(shí)間也是不確定的,升級(jí)要求客戶安裝新版軟件,運(yùn)行后自動(dòng)升級(jí)。
那就真的不能在生產(chǎn)環(huán)境使用呢?
解決方案:
概要描述:
解決的思路其實(shí)就是自動(dòng)升級(jí),但是在判斷需要升級(jí)時(shí),才自動(dòng)升級(jí),同時(shí)升級(jí)前先備份數(shù)據(jù)庫。
具體流程
程序內(nèi)每次有數(shù)據(jù)庫變更,發(fā)布版本時(shí),修改程序內(nèi)對(duì)應(yīng)版本。比如最開始是1000,最新是1100
在數(shù)據(jù)庫增加SysConfig表,字段包含DbVer表示當(dāng)前數(shù)據(jù)庫版本號(hào)
在數(shù)據(jù)庫增加DbLog表,記錄數(shù)據(jù)庫升級(jí)日志,此項(xiàng)可選
在首次安裝時(shí),檢查數(shù)據(jù)庫文件不存在,表示首次安裝,首次安裝時(shí)創(chuàng)建SysConfig表和DbLog表,同時(shí)更新SysConfig表DbVer為程序中記錄版本號(hào)。增加DbLog表日志
以后再次運(yùn)行時(shí),先獲取SysConfig表DbVer,判斷與程序中是否一致,
如果數(shù)據(jù)庫比程序中大,說明運(yùn)行低版本的程序,根據(jù)情況可以禁止運(yùn)行。也可以不同步數(shù)據(jù)庫,繼續(xù)運(yùn)行,根據(jù)實(shí)際情況決定。如果對(duì)程序和數(shù)據(jù)庫一致性要求比較高,可以禁止運(yùn)行。
如果數(shù)據(jù)庫比程序小,說明數(shù)據(jù)庫需要升級(jí),此時(shí)先備份現(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)用程序的主入口點(diǎn)。
/// </summary>
[STAThread]
static void Main()
{
try
{
//數(shù)據(jù)庫是否存在,用于插入初始數(shù)據(jù),必須在freesql實(shí)例化前判斷,因?yàn)閷?shí)例化時(shí)會(huì)自動(dòng)創(chuàng)建數(shù)據(jù)庫
var custDbPathExists = File.Exists(CustDbPath);
//deebug自動(dòng)同步實(shí)體結(jié)構(gòu)到數(shù)據(jù)庫,release手動(dòng)同步
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自動(dòng)同步實(shí)體結(jié)構(gòu)到數(shù)據(jù)庫,release手動(dòng)同步
.UseMonitorCommand(cmd => Console.WriteLine($"線程:{cmd.CommandText}\r\n"))
.Build(); //請(qǐng)務(wù)必定義成 Singleton 單例模式
if(syncDbStructure)
{
//主要用于開發(fā)模式下,讓數(shù)據(jù)庫修改快速生效,不加此句時(shí),只有在用到表時(shí)才會(huì)同步
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ù)庫版本不一樣,需要升級(jí)
//備份數(shù)據(jù)庫
File.Copy(CustDbPath, Application.StartupPath + $"\\數(shù)據(jù)庫\\cust{DateTime.Now:yyyyMMddHHmmss}.db");
//升級(jí)數(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(), "出錯(cuò)啦", 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)建時(shí)間
/// </summary>
[Column(ServerTime = DateTimeKind.Local, CanUpdate = false)]
public DateTime CreateTime { get; set; }
/// <summary>
/// 修改時(shí)間
/// </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)建時(shí)間
/// </summary>
[Column(ServerTime = DateTimeKind.Local, CanUpdate = false)]
public DateTime CreateTime { get; set; }
/// <summary>
/// 修改時(shí)間
/// </summary>
[Column(ServerTime = DateTimeKind.Local, CanUpdate = true)]
public DateTime UpdateTime { get; set; }
}
}
總結(jié):
以前是手寫的SQL語句,現(xiàn)在用FreeSql確實(shí)方便多了。
以上就是c#使用FreeSql生產(chǎn)環(huán)境自動(dòng)升級(jí)備份數(shù)據(jù)庫的詳細(xì)內(nèi)容,更多關(guān)于c# 用FreeSql自動(dòng)升級(jí)備份數(shù)據(jù)庫的資料請(qǐng)關(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è)計(jì)與實(shí)現(xiàn)
- C#窗體-數(shù)據(jù)庫連接及登錄功能的實(shí)現(xiàn)案例
- C#連接SQL Server數(shù)據(jù)庫的實(shí)例講解
- C#連接Oracle數(shù)據(jù)庫字符串(引入DLL)的方式
- C# Ado.net實(shí)現(xiàn)讀取SQLServer數(shù)據(jù)庫存儲(chǔ)過程列表及參數(shù)信息示例
相關(guān)文章
基于C#實(shí)現(xiàn)的多邊形沖突檢測(cè)實(shí)例
這篇文章主要給大家介紹了基于C#實(shí)現(xiàn)的多邊形沖突檢測(cè)的相關(guān)資料,文中介紹的方法并未使用第三方類庫,可以完美解決這個(gè)問題,需要的朋友可以參考下2021-07-07
unity實(shí)現(xiàn)多點(diǎn)觸控代碼
這篇文章主要介紹了unity實(shí)現(xiàn)多點(diǎn)觸控代碼,我最近在學(xué)習(xí)Unity游戲引擎。先從Unity平面開始,本章介紹Unity 平面上的多點(diǎn)觸摸。有需要的小伙伴參考下。2015-03-03
c# Rank屬性與GetUpperBound方法的深入分析
本篇文章是對(duì)c#中的Rank屬性與GetUpperBound方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
Unity 實(shí)現(xiàn)給物體動(dòng)態(tài)添加事件
這篇文章主要介紹了Unity 實(shí)現(xiàn)給物體動(dòng)態(tài)添加事件的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-04-04
C#日期格式字符串的相互轉(zhuǎn)換操作實(shí)例分析
這篇文章主要介紹了C#日期格式字符串的相互轉(zhuǎn)換操作,結(jié)合實(shí)例形式分析了C#日期格式字符串的相互轉(zhuǎn)換操作函數(shù)與相關(guān)使用技巧,需要的朋友可以參考下2019-08-08
Unity接入百度AI實(shí)現(xiàn)果蔬識(shí)別
本文將介紹如何利用Unity接入百度AI從而實(shí)現(xiàn)果蔬識(shí)別,可以做到識(shí)別近千種水果和蔬菜的名稱,可自定義返回識(shí)別結(jié)果數(shù)。感興趣的小伙伴可以了解一下2022-02-02
快速了解如何在.NETCORE中使用Generic-Host建立主機(jī)
這篇文章主要介紹了如何在.NETCORE中使用Generic-Host建立主機(jī),文中代碼非常詳細(xì),可供大家參考,感興趣的朋友不妨閱讀完2020-05-05

