c#使用FreeSql生产环境时自动升级备份数据库
作者:一级码农VIP 发布时间:2024-01-22 15:56:01
目录
项目场景:
解决方案:
概要描述:
详细说明:
总结:
项目场景:
使用FreeSql,包含所有的ORM数据库,都会存在这样的问题。在codefirst模式下,根据代码自动更新数据库,都建议不要在生产环境使用。为什么呢?
其实不建议使用,主要是根据代码自动生成数据时,极有可能会造成数据的丢失,比如修改字段类型,自动更新的结果可能并不是自己想的。
但是有一些使用场景是需要在生产环境自动升级的,比如
我们有一个CS客户端的产品,客户本地离线使用,客户本地部署,数据库也是本地数据库,版本从1000,迭代到了1100,中间发布了100个版本。这中间可能有多次数据库更改。我们的客户也可能遍布全国各地,版本也都不相同。客户如果没有新的需求,可能会一直使用当前旧版本,只有在有新的需求,或者想使用新的功能时,才会升级版本。所以升级的时间也是不确定的,升级要求客户安装新版软件,运行后自动升级。
那就真的不能在生产环境使用呢?
解决方案:
概要描述:
解决的思路其实就是自动升级,但是在判断需要升级时,才自动升级,同时升级前先备份数据库。
具体流程
程序内每次有数据库变更,发布版本时,修改程序内对应版本。比如最开始是1000,最新是1100
在数据库增加SysConfig表,字段包含DbVer表示当前数据库版本号
在数据库增加DbLog表,记录数据库升级日志,此项可选
在首次安装时,检查数据库文件不存在,表示首次安装,首次安装时创建SysConfig表和DbLog表,同时更新SysConfig表DbVer为程序中记录版本号。增加DbLog表日志
以后再次运行时,先获取SysConfig表DbVer,判断与程序中是否一致,
如果数据库比程序中大,说明运行低版本的程序,根据情况可以禁止运行。也可以不同步数据库,继续运行,根据实际情况决定。如果对程序和数据库一致性要求比较高,可以禁止运行。
如果数据库比程序小,说明数据库需要升级,此时先备份现有数据库,然后执行同步数据库。
详细说明:
直接上代码,比啥都清楚
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>
/// 客户数据库路径
/// </summary>
private static string CustDbPath = Application.StartupPath + $"\\数据库\\cust.db";
/// <summary>
/// 数据库ORM
/// </summary>
public static IFreeSql fsql;
/// <summary>
/// 服务器数据库版本
/// </summary>
private static int ServerDbVer = 1000;
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
try
{
//数据库是否存在,用于插入初始数据,必须在freesql实例化前判断,因为实例化时会自动创建数据库
var custDbPathExists = File.Exists(CustDbPath);
//deebug自动同步实体结构到数据库,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自动同步实体结构到数据库,release手动同步
.UseMonitorCommand(cmd => Console.WriteLine($"线程:{cmd.CommandText}\r\n"))
.Build(); //请务必定义成 Singleton 单例模式
if(syncDbStructure)
{
//主要用于开发模式下,让数据库修改快速生效,不加此句时,只有在用到表时才会同步
fsql.CodeFirst.SyncStructure(GetTypesByTableAttribute());
}
if (custDbPathExists == false)
{
//数据库文件不存在,表示是首次安装
fsql.CodeFirst.SyncStructure(GetTypesByTableAttribute());
var sysConfig = new SysConfig();
sysConfig.DbVer = ServerDbVer;
var dbResult = fsql.Insert(sysConfig).ExecuteAffrows();
if (dbResult <= 0)
throw new Exception("初始数据库失败。");
var row = new DbLog();
row.DbVer = ServerDbVer;
fsql.Insert(row).ExecuteAffrows();
}
int localDbVer = fsql.Select<SysConfig>().First().DbVer;
if (localDbVer != ServerDbVer)
{
//数据库版本不一样,需要升级
//备份数据库
File.Copy(CustDbPath, Application.StartupPath + $"\\数据库\\cust{DateTime.Now:yyyyMMddHHmmss}.db");
//升级数据库
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>
/// 创建时间
/// </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>
/// 创建时间
/// </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; }
}
}
总结:
以前是手写的SQL语句,现在用FreeSql确实方便多了。
来源:https://www.cnblogs.com/zhupengfei/p/14137128.html


猜你喜欢
- Python获取多线程返回结果在 Python 的多线程中,有时候我们会需要每一个线程中返回的结果。然而,在经过我的多番尝试、以及网上各种博
- /* JS代码部分 */ 3 const date = new Date()const years = []const months = [
- 本文讨论 MySQL 的备份和恢复机制,以及如何维护数据表,包括最主要的两种表类型:MyISAM 和 Innodb,文中设计的 MySQL
- 1. 命令行不知道大家在日常操作redis时用什么可视化工具呢?以前总觉得没有什么太好的可视化工具,于是问了一个业内朋友。对方回:你还用可视
- 在许多情况下,当迁移至SQL Server 2008之前必须了解那些反对和放弃功能的具体情况。下文是几个主要功能在兼容性上的问题列表:1.S
- 从BbsXp提出来的生肖函数Zodiac(birthday)。使用方法:birthday为把要判断的出生时间,如2008-3-24 20:0
- python默认使用的是国外镜像,有时候下载非常慢,最快的办法就是在下载命令中增加国内源:常用的国内源如下:清华大学:https://pyp
- 之前遇到一个场景是这样的:我在自己的电脑上需要用mongodb图形客户端,但是mongodb的服务器地址没有对外网开放,只能通过先登录主机A
- 前言本文执行环境typescript,版本4.7.4不使用typescript的计算能力,通过类型来实现快排元组快排能否将元组 [3, 1,
- 本文实例讲述了Python实现将蓝底照片转化为白底照片功能。分享给大家供大家参考,具体如下:import cv2import numpy a
- python书籍信息爬虫示例,供大家参考,具体内容如下背景说明需要收集一些书籍信息,以豆瓣书籍条目作为源,得到一些有效书籍信息,并保存到本地
- 本文实例讲述了Python 实现的微信爬虫。分享给大家供大家参考,具体如下:单线程版:import urllib.requestimport
- 1. 判断表单元素是否存在(一) if("periodPerMonth" in document.theForm) {
- 富文本编辑器,Rich Text Editor, 简称 RTE, 它提供类似于 Microsoft Word 的编辑功能,容易被不会编写 H
- 本文基本使用谷歌翻译加上自己的理解,权当加深记忆。npm简介qs 是一个增加了一些安全性的查询字符串解析和序列化字符串的库。主要维护者:Jo
- 创建RandomWalk类为模拟随机漫步,我们将创建一个RandomWalk类,随机选择前进方向,这个类有三个属性,一个存储随机漫步的次数,
- 一、问题的引入opencv在图像处理方面有着非常强大的功能,当我们需要使用opencv进行一些图像的矫正工作时,我们通常需要找到原图的一些关
- javascript单线程JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及
- 安装python中文分词库jieba法1:Anaconda Prompt下输入conda install jieba法2:Terminal下
- Asp开发 联通CDMA以下是在开发wap中的随笔,其中一些对于“老鸟”来说,谈不上什么,希望对初学者有所帮助,大家有什么小技巧,欢迎顶上来