项目场景:
使用FreeSql,包含所有的ORM数据库,都会存在这样的问题。在codefirst模式下,根据代码自动更新数据库,都建议不要在生产环境使用。为什么呢?
其实不建议使用,主要是根据代码自动生成数据时,极有可能会造成数据的丢失,比如修改字段类型,自动更新的结果可能并不是自己想的。
但是有一些使用场景是需要在生产环境自动升级的,比如
我们有一个CS客户端的产品,客户本地离线使用,客户本地部署,数据库也是本地数据库,版本从1000,迭代到了1100,中间发布了100个版本。这中间可能有多次数据库更改。我们的客户也可能遍布全国各地,版本也都不相同。客户如果没有新的需求,可能会一直使用当前旧版本,只有在有新的需求,或者想使用新的功能时,才会升级版本。所以升级的时间也是不确定的,升级要求客户安装新版软件,运行后自动升级。
那就真的不能在生产环境使用呢?
解决方案:
概要描述:
解决的思路其实就是自动升级,但是在判断需要升级时,才自动升级,同时升级前先备份数据库。
具体流程
程序内每次有数据库变更,发布版本时,修改程序内对应版本。比如最开始是1000,最新是1100
在数据库增加SysConfig表,字段包含DbVer表示当前数据库版本号
在数据库增加DbLog表,记录数据库升级日志,此项可选
在首次安装时,检查数据库文件不存在,表示首次安装,首次安装时创建SysConfig表和DbLog表,同时更新SysConfig表DbVer为程序中记录版本号。增加DbLog表日志
以后再次运行时,先获取SysConfig表DbVer,判断与程序中是否一致,
如果数据库比程序中大,说明运行低版本的程序,根据情况可以禁止运行。也可以不同步数据库,继续运行,根据实际情况决定。如果对程序和数据库一致性要求比较高,可以禁止运行。
如果数据库比程序小,说明数据库需要升级,此时先备份现有数据库,然后执行同步数据库。
详细说明:
直接上代码,比啥都清楚
program.cs文件代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
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自动升级备份数据库的资料请关注服务器之家其它相关文章!
原文链接:https://www.cnblogs.com/zhupengfei/p/14137128.html