C# + SQLiteExpert 进行(cipher)加密数据库开发+Costura.Fody 清爽发布

一:让 SQLiteExpert 支持(cipher)加密数据库

SQLiteExpert 作为SQlite 的管理工具,默认不支持加密数据库的,使其成为支持(cipher)加密数据库的管理工具,需要添加e_sqlcipher.dll (复制到SQLiteExpertPro32/64.exe 同级目录即可,从哪里来的这个问题:你可以直接往后面下载链接下,也可以跟随文章知道从哪里来的。最好是知道从哪里来的,也许我放链接的版本在未来有新版本更替,我也就不更新下载链接了。),并在其设置里面进行勾选就能激活加密数据库支持。如下图所示(几个关键点已经标记),需要注意的是SQLiteExpert 32位/64位需要与e_sqlcipher.dll 32位/64位匹配,否则在32位版的SQLiteExpert 是看不到64位的e_sqlcipher.dll。

加入成功后,打开或者新建数据库都有加密选项

(新建数据库)

(打开加密数据库)

这样到此可以完整的处理了SQLiteExpert 支持加密

由于SQLiteExpert 只有windows 版本,linux 平台的cipher加密支持库也就不打包了。对于跨平台的SQLite gui 也许类似,上传的压缩包就只有windows平台dll。

下载链接在顶部,压缩包结构如下:

二. .Net C# 连接(cipher)加密的SQlite数据库

nuget

1、SQLitePCLRaw.bundle_e_sqlcipher

2、Microsoft.Data.Sqlite

3、Costura.Fody (如果不需要考虑发布洁癖(单文件,全部外围DLL聚合),就没必要。)

直接debug,生成一堆内容,我随便建立了个VS 工程(sqlitedemo) debug目录大致如下:

runtime 内容如下:(也就是各种平台的(cipher)sqlite lib),前面的e_sqlcipher.dll取材就是从这里取得。

debug 生成的很多,也就是刚才说的发布生成洁癖的问题,如果你在意,发布时候选择输出好平台,runtime可以自动减少,但是依旧会生成其他dll。

那就采用Costura.Fody

编辑项目内 FodyWeavers.xml 文件(nuget过了会自动生成该文件),文件内容修改如下:

bash 复制代码
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
  <Costura >
    <Unmanaged64Assemblies>
      e_sqlcipher
      e_sqlite3
    </Unmanaged64Assemblies>
    <Unmanaged32Assemblies>
      e_sqlcipher
      e_sqlite3
    </Unmanaged32Assemblies>
  </Costura>
</Weavers>

再编辑 解决方案文件(右边第一箭头那里双击)

主要语句加入 (我选择的x64版本的Exe)

<RuntimeIdentifier>win-x64</RuntimeIdentifier>

这样,右键点击 解决方案->重新生成解决方案 (这里要注意,要重新整个解决方案才行。更改解决方案文件,直接debug会有问题。)

最终生成输出内容如下:

其他乱七八糟的dll没有了,清爽吧?!

再来看相关C# 连接Sqlite 操作的代码:先上SqliteHelper,顺便也推荐一下 Cody AI生成的,我用了很长时间,免费且好用(面向编程)。

cs 复制代码
    public class SQLiteHelper
    {
        private readonly string _connectionString;

        public SQLiteHelper(string dbPath, string password = null)
        {
            var builder = new SqliteConnectionStringBuilder
            {
                DataSource = dbPath,
                Mode = SqliteOpenMode.ReadWriteCreate
            };

            if (!string.IsNullOrEmpty(password))
            {
                builder.Password = password;
            }

            _connectionString = builder.ConnectionString;
        }

        public int ExecuteNonQuery(string sql, List<SqliteParameter> parameters = null)
        {
            using (var connection = new SqliteConnection(_connectionString))
            {
                connection.Open();
                using (var command = connection.CreateCommand())
                {
                    command.CommandText = sql;
                    if (parameters != null)
                    {
                        command.Parameters.AddRange(parameters);
                    }
                    return command.ExecuteNonQuery();
                }
            }
        }

        public T ExecuteScalar<T>(string sql, List<SqliteParameter> parameters = null)
        {
            using (var connection = new SqliteConnection(_connectionString))
            {
                connection.Open();
                using (var command = connection.CreateCommand())
                {
                    command.CommandText = sql;
                    if (parameters != null)
                    {
                        command.Parameters.AddRange(parameters);
                    }
                    var result = command.ExecuteScalar();
                    return (T)Convert.ChangeType(result, typeof(T));
                }
            }
        }

        public List<T> ExecuteQuery<T>(string sql, List<SqliteParameter> parameters = null) where T : new()
        {
            var result = new List<T>();
            using (var connection = new SqliteConnection(_connectionString))
            {
                connection.Open();
                using (var command = connection.CreateCommand())
                {
                    command.CommandText = sql;
                    if (parameters != null)
                    {
                        command.Parameters.AddRange(parameters);
                    }

                    using (var reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            var item = new T();
                            for (int i = 0; i < reader.FieldCount; i++)
                            {
                                var property = typeof(T).GetProperty(reader.GetName(i), BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
                                if (property != null && !reader.IsDBNull(i))
                                {
                                    property.SetValue(item, Convert.ChangeType(reader.GetValue(i), property.PropertyType));
                                }
                            }
                            result.Add(item);
                        }
                    }
                }
            }
            return result;
        }

        public void ExecuteTransaction(Action<SqliteConnection> action)
        {
            using (var connection = new SqliteConnection(_connectionString))
            {
                connection.Open();
                using (var transaction = connection.BeginTransaction())
                {
                    try
                    {
                        action(connection);
                        transaction.Commit();
                    }
                    catch
                    {
                        transaction.Rollback();
                        throw;
                    }
                }
            }
        }
    }
}

调用如下:

SQLiteHelper 构造函数,第一个参数数据库路径文件全名,第二个参数数据库密码

cs 复制代码
   SQLiteHelper SLH = new SQLiteHelper("D:\\Manage\\Documents\\db", "TEST");
   const int batchSize = 100000;
   const string insertSql = "INSERT INTO Student (F_ID, F_Name) VALUES (@F_ID, @F_Name)";

   SLH.ExecuteTransaction(connection =>
   {
       using var command = connection.CreateCommand();
       command.CommandText = insertSql;
       command.Parameters.Add("@F_ID", SqliteType.Text);
       command.Parameters.Add("@F_Name", SqliteType.Text);

       for (int i = 0; i < batchSize; i++)
       {
           command.Parameters["@F_ID"].Value = Guid.NewGuid().ToString();
           command.Parameters["@F_Name"].Value = $"John{i}";
           command.ExecuteNonQuery();
       }
   });

密码错误则在这里报错:

这样既可以C# 开发加密数据库又可以在外部用外部工具直接编辑加密数据库的环境就达成了。

后话:

选择SQLiteExpert 是界面要黑一点,可能不是最好用的,但黑色看起来眼睛舒服一点,欢迎推荐一些。

相关推荐
Ai 编码助手25 分钟前
MySQL中distinct与group by之间的性能进行比较
数据库·mysql
陈燚_重生之又为程序员41 分钟前
基于梧桐数据库的实时数据分析解决方案
数据库·数据挖掘·数据分析
caridle43 分钟前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
白云如幻44 分钟前
MySQL排序查询
数据库·mysql
萧鼎1 小时前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
^velpro^1 小时前
数据库连接池的创建
java·开发语言·数据库
荒川之神1 小时前
ORACLE _11G_R2_ASM 常用命令
数据库·oracle
IT培训中心-竺老师1 小时前
Oracle 23AI创建示例库
数据库·oracle
小白学大数据1 小时前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫
time never ceases2 小时前
使用docker方式进行Oracle数据库的物理迁移(helowin/oracle_11g)
数据库·docker·oracle