项目场景:

使用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确实方便多了。感觉FreeSql。

以上方案有需要改进的,或者好的建议,希望大家评论留言。

FreeSql生产环境自动升级数据库解决方案的更多相关文章

  1. 系统环境: CentOS 64位+千万不要在生产环境中升级glibc!

    # cd /lib64# LD_PRELOAD=/lib64/libc-2.15.so ln -sf /lib64/libc-2.15.so libc.so.6 libc-2.15.so 这个文件名根 ...

  2. 生产环境中,数据库升级维护的最佳解决方案flyway

    官网:https://flywaydb.org/ 转载:http://casheen.iteye.com/blog/1749916 1.  引言 想到要管理数据库的版本,是在实际产品中遇到问题后想到的 ...

  3. 生产环境中mysql数据库由主从关系切换为主主关系

    目录 一.清除原从数据库数据及主从关系 1.1.关闭主从数据库原有的主从关系 1.2.清除从数据库原有数据 二.将主库上的数据备份到从库 2.1.备份主库数据到从库 2.2.在从库使用tsc.sql文 ...

  4. [MySQL-MM] 生产环境自动恢复MM中一台M2库的过程,分享从零开始写的自动化重建脚本以及思路 (转)

    必须是MM架构,而且一台主库M1是完好无损的,一台主库M2可以根据M1主库来进行重建:如果MS架构,自己可以稍微做一下脚本修改动作,也能使用,架构如下图所示: 3  总体思路,建立主脚本a_build ...

  5. linux日志审计项目案例实战(生产环境日志审计项目解决方案)

    所谓日志审计,就是记录所有系统及相关用户行为的信息,并且可以自动分析.处理.展示(包括文本或者录像) 推荐方法:sudo配合syslog服务,进行日志审计(信息较少,效果不错) 1.安装sudo命令. ...

  6. 生产环境自动备份win服务器所有web项目(IIS+项目代码)

    @echo offrem 功能:每月自动备份本服务器所有web项目rem 日期:2022.3.10rem 制作人:zl rem 定义变量Y为备份时间:YYYYMMset y=%date:~0,4%%d ...

  7. 黄聪:禁止wordpress版本自动升级的解决方案

    在WordPress配置文件中找到wp-config.php,添加如下常量 define( 'AUTOMATIC_UPDATER_DISABLED', true );

  8. 理解Docker(6):若干企业生产环境中的容器网络方案

    本系列文章将介绍 Docker的相关知识: (1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 ...

  9. MySQL 8 升级数据库

    开始升级前 因为从MySQL 8.0 到MySQL 5.7,或者从MySQL 8.0 到之前的 MySQL 8.0版本都是不支持的.所有在在升级前要做好数据库备份,包括mysql 系统schema(数 ...

  10. LNMP一键安装包 PHP自动升级脚本

    LNMP一键安装包 PHP自动升级脚本 2011年03月15日 上午 | 作者:VPS侦探 前一段时间完成了lnmp一键安装包的PHP自动升级脚本,今天发布出来,如果想升级PHP版本的lnmp用户可以 ...

随机推荐

  1. 实操开源版全栈测试工具RunnerGo安装(二)Linux安装

    手动安装(支持Linux.MacOS.Windows) Linux安装步骤 以debian系统为例,其他linux系统参考官方文档:https://docs.docker.com/engine/ins ...

  2. 【Android逆向】修改so文件方式修改程序行为

    1. 还是之前的那个apk 链接:https://pan.baidu.com/s/1vKC1SevvHfeI7f0d2c6IqQ 密码:u1an 尝试使用 010Editor来修改so文件 2. 使用 ...

  3. 【Azure Function】修改Function执行的Timeout时间

    问题描述 Azure Function默认的Timeout时间是否可以调整呢? 问题解答 可以的,根据创建Function的时候选择的定价层不同,Function 默认的Timeout时间也不同. 消 ...

  4. 【Azure 存储服务】Storage Account Blob 使用REST API如何获取磁盘大小(Content-Length), IOPS信息

    问题描述 1)关于使用Rest API获取非托管磁盘信息比如获取磁盘大小 2)关于使用Rest API获取非托管磁盘信息比如iops 问题答案 #1:关于使用Rest API获取非托管磁盘信息比如获取 ...

  5. NebulaGraph is nothing without you | 社区 2023 年度人物合集

    在去年的年度人物 回顾中,我们看到了形形色色的人们,他们当中有帮 NebulaGraph 捉 bug 的小能手,也有通过用回复来解答他人疑惑的启蒙者-在今年(2023 年),我们这个整点不一样的,将镜 ...

  6. ubuntu22.04安装配置redis

    本操作在虚拟机上 安装Redis 1)更新系统 sudo apt update sudo apt upgrade 2)安装Redis sudo apt install redis-server 3)测 ...

  7. STL-unordered_map,unordered_set模拟实现

    unordered_set #pragma once #include"28hashtable_container.h" namespace test { //template & ...

  8. Java 类中属性的使用

    1 类中属性的使用: 2 * 属性(成员变量) 局部变量 3 * 1.相同点: 4 * 定义变量的个格式: 数据类型 变量名 = 变量值 5 * 先声明 后使用 6 * 变量都有其对应的作用域 7 * ...

  9. Java 练习题 5岁的狗按人的年龄计算的话,前两年每一年是人的 10.5岁,之后每一年 * 增加4岁。如果5岁的狗、相当于人的多少年龄 * 10.5 + 10.5 + 4 +4 +4=33岁

    1 /*** 2 * 练习题 3 * 5岁的狗按人的年龄计算的话,前两年每一年是人的 10.5岁,之后每一年 4 * 增加4岁.如果5岁的狗.相当于人的多少年龄 5 * 10.5 + 10.5 + 4 ...

  10. Alertmanager钉钉告警

    一.部署alertmanager 1.1 创建目录 mkdir -p /deploy/app/alertmanager/config chmod -R 777 /deploy/app/alertman ...