c#使用FreeSql生产环境时自动升级备份数据库

目录
  • 项目场景:
  • 解决方案:
    • 概要描述:
  • 详细说明:
  • 总结:

项目场景:

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

以上就是c#使用FreeSql生产环境自动升级备份数据库的详细内容,更多关于c# 用FreeSql自动升级备份数据库的资料请关注我们其它相关文章!

(0)

相关推荐

  • C#从数据库读取图片并保存的两种方法

    方式一: 数据库用的是SQL 2008,数据表中存放的是图片的二进制数据,现在把图片以一种图片格式(如.jpg)导出,然后存放于指定的文件夹中,实现方式如下: byte[] bytImg = (byte[])myDAL.DbHelperSQL.Query("SELECT F_Photo FROM myTable WHERE ID=1").Tables[0].Rows[0][0]; if (bytImg != null) { MemoryStream ms = new MemoryStr

  • C# TreeView从数据库绑定数据的示例

    封装成一个函数,方便直接调用 //绑定TrreView private void InitModuleTree(DataTable dt) { //清空treeview上所有节点 this.tree_Role.Nodes.Clear(); int[] gen = new int[dt.Rows.Count]; //用于存储父节点Tag int[] zi = new int[dt.Rows.Count]; //用于存储子节点Tag for (int i = 0; i < gen.Length; i

  • C#窗体-数据库连接及登录功能的实现案例

    本篇文章介绍了C#窗体的数据库连接及登录功能的实现 工具或平台:VS2010.sqlserver2012 1.创建完窗体后,点击数据,选择添加新数据源 2.选择数据库 3.选择数据集 4.新建连接-Microsoft SQL Server,添加完测试一下 5.添加数据库-注意把连接字符串部分复制一下,一会儿要用的 6.保存连接字符串到配置文件中 7.选择需要用数据库的那些部分,由于我的工程较小,仅选择了表,读者根据需要自行添加 8.引入与数据库相关的命名空间(using System.Data.

  • C#连接Oracle数据库字符串(引入DLL)的方式

    需求: 从一台Oracle数据库获取数据,本以为是很简单的事情,直接将原来的SqlClient换成OracleClient调用,结果远没自己想的简单.要么安装Oracle客户端,要么安装PLSQL.网上这方面搜索后,太多的文章,还要不停的去测试.最后找个引入外部类库的方式.这个DLL其实是Oracle为C#专门提供的,在它的官方也可以下载到(不过找起来很麻烦). 这里我就把这个方案和dll分享给大家. 点击这里下载 DEMO示例 using Oracle.ManagedDataAccess.Cl

  • C#使用SqlServer作为日志数据库的设计与实现

    前言 做一个简单的日志数据库 功能不需要特别繁琐 主要就是记录普通日志和错误日志(INFO,ERROR) 用数据库作为日志有好处也有坏处 相比于文本来说 更加容易操作 后期查看日志可以根据时间筛选 当然要求也多了点 没那么灵活了 首先你的PC上还要安装一个SqlServer 本来是想用log4net配置去实现的 发现配置很繁琐 决定自己设计一个 肯定有不少不足之处 分为以下几个步骤 1.建立日志数据表 都用一个表来存放,那么字段就要多设置一个 用来区分不同的日志类型 具体怎么设置 也很简单 字段

  • C#连接SQL Server数据库的实例讲解

    C#连接数据库:Connection对象 1.Connection对象概述 Connection对象是一个连接对象,主要功能是建立与物理数据库的连接.其主要包括4种访问数据库的对象类,也可称为数据提供程序,分别介绍如下. SQL Server数据提供程序,位于System.Data.SqlClient命名空间. ODBC数据提供程序,位于System.Data.Odbc命名空间. OLEDB数据提供程序,位于System.Data.OleDb命名空间. Oracle数据提供程序,位于System

  • C# 创建MDB数据库、并存放表格数据的案例

    下面是近期学习C#连接MDB数据库,通过路径创建MDB数据库,根据名字创建创建对用MDB数据库中的表格,再通过DataTable创建一致的表并将数据放入,这是一个类,用完之后记得用Close()方法. 添加引用: 目的是//创建Catalog目录类 ADOX.CatalogClass catalog = new ADOX.CatalogClass(); using System; using System.Collections.Generic; using System.Linq; using

  • C#连接SQL数据库和查询数据功能的操作技巧

    大数据时代在编程可能需要用到一些文本内容,不可能全部写到代码里,不好更改,用户也不方便使用 所以需要用到我们的数据库来保存这些数据,直接更改数据 SQL: 下载地址:https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 1.下载后打开选择登录:Windows身份验证 2.创建登录的账号和密码(右键创建) 3.创建数据库表 表的右键新建即可 "dbo.table_1" 就是创建成功的 4.导入数据 这里以 信息表为

  • C# Ado.net实现读取SQLServer数据库存储过程列表及参数信息示例

    本文实例讲述了C# Ado.net读取SQLServer数据库存储过程列表及参数信息的方法.分享给大家供大家参考,具体如下: 得到数据库存储过程列表: select * from dbo.sysobjects where OBJECTPROPERTY(id, N'IsProcedure') = 1 order by name 得到某个存储过程的参数信息:(SQL方法) select * from syscolumns where ID in (SELECT id FROM sysobjects

  • c#使用FreeSql生产环境时自动升级备份数据库

    目录 项目场景: 解决方案: 概要描述: 详细说明: 总结: 项目场景: 使用FreeSql,包含所有的ORM数据库,都会存在这样的问题.在codefirst模式下,根据代码自动更新数据库,都建议不要在生产环境使用.为什么呢? 其实不建议使用,主要是根据代码自动生成数据时,极有可能会造成数据的丢失,比如修改字段类型,自动更新的结果可能并不是自己想的. 但是有一些使用场景是需要在生产环境自动升级的,比如 我们有一个CS客户端的产品,客户本地离线使用,客户本地部署,数据库也是本地数据库,版本从100

  • mysql自动定时备份数据库的最佳方法(windows服务器)

    网上有很多关于window下Mysql自动备份的方法,可是真的能用的也没有几个,有些说的还非常的复杂,难以操作. 我们都知道mssql本身就自带了计划任务可以用来自动备份,可是mysql咱们要怎么样自动有备份呢? 教大家一个最简单的方法. 这个方法是用bat批处理来完成的. 假想环境:MySQL 安装位置:D:\Program Files\MySQL\MySQL Server 5.0\data 如图: 数据库名称为:952game数据库备份目的地:d:\db_bak\ (你想把数据库备份到哪个盘

  • Nginx1.21.6生产环境升级步骤

    现在要把nginx旧版本升级到新版,所以针对生产环境的升级做一个平滑升级教程,如下:服务器:CentOS7旧版本:nginx-1.19.5新版本:nginx-1.21.6 升级步骤: 1.解压新版本nginx tar -zxvf nginx-1.21.6.tar.gz 2.进入安装目录,开始编译 # 编译应与之前版本的编译相同,我这里之前编辑就是默认,所以不需要改动 ./configure 3.make,一定不要make install!!! make 4.替换二进制文件(把新版本的二进制执行文

  • Nginx生产环境平滑升级的实现

    目录 一.背景 二.升级方案 三.操作流程 一.背景 最近遇到一个比较尴尬而又实际的问题,那就是我们生产环境使用的Nginx是Centos6的老古董.业务需求需要加载Nginx的一个模块来实现,但是版本太老了,需要Nginx1.18之后才能支持,而我们的是Nginx1.12. 那升级Nginx是我们要做的事情.但是在生产环境你要考虑的东西很多,不像测试服,Nginx停掉服务,重新编译新的版本再启动. 我们线上的服务需要不间断地提供服务,否则会对业务产生经济损失. 那有什么方案能平滑升级Nginx

  • Electron实现应用打包、自动升级过程解析

    上次成功搭建了vue + electron的helloworld程序,这次将electron应用打包及自动升级的流程梳理了一下. 1. 应用打包 使用electron builder打包只需要在vue.config.js中配置即可,这里需要注意的是,默认情况下electron builder打包出来的安装程序是不能修改安装目录的,需要allowToChangeInstallationDirectory这个配置设置为true. // see https://cli.vuejs.org/config

  • flyway实现java 自动升级SQL脚本的问题及解决方法

    为什么要用Flyway 在日常开发中,我们经常会遇到下面的问题: 自己写的SQL忘了在所有环境执行: 别人写的SQL我们不能确定是否都在所有环境执行过了: 有人修改了已经执行过的SQL,期望再次执行: 需要新增环境做数据迁移: 每次发版需要手动控制先发DB版本,再发布应用版本; 其它场景... 由于项目需求的变化,或者前期设计缺陷,导致在后期需要修改数据库,这应该是一个比较常见的事情,如果项目还没上线,你可能把表删除了重新创建,但是如果项目已经上线了,就不能这样简单粗暴了,每次运维部署项目,还得

  • 基于在生产环境中使用php性能测试工具xhprof的详解

    xhprof 是facebook开源出来的一个php性能测试工具,也可以称之为profile工具,这个词不知道怎么翻译才比较达意.跟之前一直使用的xdebug相比,有很多类似之处.以前对xdebug有一些记录还可以供参考,但是它的缺点是对性能影响太大,即便是开启了profiler_enable_trigger参数,用在生产环境中也是惨不忍睹,cpu立刻就飙到high.而xhprof就显得很轻量,是否记录profile可以由程序控制,因此,用在生产环境中也就成为一种可能.在它的文档上可以看到这样一

  • 基于Vue生产环境部署详解

    前面的话 开发时,Vue 会提供很多警告来帮助解决常见的错误与陷阱.生产时,这些警告语句却没有用,反而会增加载荷量.再次,有些警告检查有小的运行时开销,生产环境模式下是可以避免的.本文将详细介绍Vue生产环境部署 生产环境 如果用 Vue 完整独立版本 (直接用 <script> 元素引入 Vue),生产时应该用精简版本 (vue.min.js) 如果用 Webpack 或 Browserify 类似的打包工具时,生产状态会在 Vue 源码中由 process.env.NODE_ENV 决定,

  • Jexus 5.8.2正式发布! 为Asp.Net Core生产环境提供平台支持

    Jexus 是一款运行于 Linux 平台,以支持  ASP.NET.PHP 为特色的集高安全性和高性能为一体的 WEB 服务器和反向代理服务器.最新版 5.8.2 已经发布,有如下更新: 1.现在大部分网站已经部署HTTPS,大家对于安全越来越重视,顺应潮流新增HTTPS多证书支持,每个网站都可以配置自己独立的SSL证书,现在有2种方式支持网站部署HTTPS. A.添加全服务器使用的SSL配置:如果需要,可以添加一个ssl配置为所有没有单独配置ssl的网站提供共享,这个配置,对支持泛域名的证书

  • 发布Angular应用至生产环境的方法

    两年前, 写过一篇使用rollup来 为生产环境编译 Angular 2 应用 的文章, 因为当时还没有 angular-cli 项目. 而如今 Angular 已经到了 7.x 版本, 对应的工具也是非常的完善, 也就不在使用 rollup 来处理 angular 项目. angular-cli 用起来虽然方便, 但是针对生产环境编译的话, 还是有一些地方要注意的, 接下来就介绍我在项目部署时的一些做法. 合理拆分功能模块, 按需加载 一个系统往往功能非常多, 因此就要根据项目的实际情况划分功

随机推荐