Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: 替换序列化被遗弃的方法 #194

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 221 additions & 0 deletions DownKyi.Core/Storage/Database/DataProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
using DownKyi.Core.Logging;
using Microsoft.Data.Sqlite;
using Microsoft.VisualBasic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Text;
using BinaryFormatDataStructure;
using System.Reflection;
using Avalonia.Controls;
using System.IO;
using System.Text.Json;
using Console = DownKyi.Core.Utils.Debugging.Console;

namespace DownKyi.Core.Storage.Database
{
public class DataProcessor
{
private readonly SqliteConnectionStringBuilder _connString;
public DataProcessor(string connString)
{
_connString = new SqliteConnectionStringBuilder(connString);
}

public SqliteConnection GetConnection(string connStr)
{
var conn = new SqliteConnection(connStr);
conn.Open();
return conn;
}

public void InitializeDatabase()
{
try
{
using (var connection = GetConnection(_connString.ConnectionString))
{
connection.Open();
var tableExists = TableExists(connection, "DataProcessor");
if (tableExists)
{
return;
}
}
ProcessColumnData();

}
catch (Exception e)
{
Console.PrintLine("Processor", e);
LogManager.Error("Processor", e);
}
}

private void ProcessColumnData()
{
string databasePath = _connString.DataSource;
if (File.Exists(databasePath))
{
var desDirectory = Path.Combine(Path.GetDirectoryName(databasePath), "backup");
Directory.CreateDirectory(desDirectory);
var desFileName = string.Concat(Path.GetFileNameWithoutExtension(databasePath),
DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss"),".db");
var desFilePath = Path.Combine(desDirectory, desFileName);
File.Create(desFilePath).Close();
File.Copy(_connString.DataSource, desFilePath, true);
}

using (var conn = GetConnection(_connString.ConnectionString))
{
var tables = GetAllTables(conn);
foreach (var tableName in tables)
{
ProcessTableWithBlob(conn, tableName);
}
CreatDataProcessorTable(conn);
}

}


private Assembly _assembly = Assembly.LoadFrom("DownKyi");


private void ProcessTableWithBlob(SqliteConnection sourceConnection, string tableName)
{
var sql = $"SELECT * FROM {tableName};";
HashSet<int> blobColumns = new HashSet<int>();
const string pragmaTableInfoSql = @"
PRAGMA table_info({0});";

ExecuteQuery(string.Format(pragmaTableInfoSql, tableName), sourceConnection, reader =>
{
while (reader.Read())
{
string typeName = reader["type"].ToString().ToLower();
if (typeName.Contains("blob"))
{
int columnIndex = reader.GetInt32(0);
blobColumns.Add(columnIndex);
}
}
});

if (blobColumns.Count == 0) return;
string updateSql = $"UPDATE {tableName} SET data = @1 WHERE id = @0;";
int primaryKeyIndex = 0;

ExecuteQuery(sql, sourceConnection, reader =>
{
while (reader.Read())
{
using (var command = sourceConnection.CreateCommand())
{
command.CommandText = updateSql;
var data = reader[1] as byte[];
if(data != null)
{
using var stream = new MemoryStream(data);

var bObj = (BinaryObject)NRBFReader.ReadStream(stream);
var targetType = _assembly.GetType(bObj.TypeName);
var instance = Activator.CreateInstance(targetType);

foreach (var prop in targetType.GetProperties())
{
try
{
string fieldName = $"<{prop.Name}>k__BackingField";
if (bObj.TryGetValue(fieldName, out var val))
{
prop.SetValue(instance, val);
}
}
catch (Exception e)
{

Console.PrintLine("ProcessTableWithBlob Properties Set发生异常: {0}", e);
LogManager.Error("ProcessTableWithBlob Properties Set()", e);
}
}

var json = JsonSerializer.Serialize(instance);
command.Parameters.AddWithValue($"@{1}", json);

command.Parameters.AddWithValue($"@{primaryKeyIndex}", reader[primaryKeyIndex]);

command.ExecuteNonQuery();
}

}
}
});
}




public void ExecuteQuery(string sql, SqliteConnection conn, Action<SqliteDataReader> action)
{
if (string.IsNullOrWhiteSpace(sql))
{
throw new ArgumentException("SQL query cannot be null or whitespace.", nameof(sql));
}

if (action == null)
{
throw new ArgumentNullException(nameof(action), "Action cannot be null.");
}
using (var command = conn.CreateCommand())
{
command.CommandText = sql;
var reader = command.ExecuteReader();
action(reader);
}
}


private List<string> GetAllTables(SqliteConnection connection)
{
const string getAllTablesSql = @"
SELECT name
FROM sqlite_master
WHERE type='table';";

List<string> tables = new List<string>();

ExecuteQuery(getAllTablesSql, connection, reader =>
{
while (reader.Read())
{
tables.Add(reader.GetString(0));
}
});

return tables;
}



private bool TableExists(SqliteConnection connection, string tableName)
{
using var command = connection.CreateCommand();
command.CommandText = $"SELECT name FROM sqlite_master WHERE type='table' AND name='{tableName}'";
var result = command.ExecuteScalar();
return result != null;
}

private void CreatDataProcessorTable(SqliteConnection connection)
{
using var command = connection.CreateCommand();
command.CommandText = @"
CREATE TABLE IF NOT EXISTS DataProcessor (
MigrationId NVARCHAR(150) NOT NULL PRIMARY KEY,
AppliedOn DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
Description TEXT);";
command.ExecuteNonQuery();
}
}
}
26 changes: 5 additions & 21 deletions DownKyi.Core/Storage/Database/DbHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,16 @@ public class DbHelper
/// 创建一个数据库
/// </summary>
/// <param name="dbPath"></param>
public DbHelper(string dbPath)
public DbHelper(string dbPath) : this(dbPath, null)
{
connStr = new SqliteConnectionStringBuilder
{
Mode = SqliteOpenMode.ReadWriteCreate,
DataSource = dbPath
}.ToString();
if (database.ContainsKey(connStr))
{
conn = database[connStr];

if (conn != null)
{
return;
}
}

conn = new SqliteConnection(connStr);
database.Add(connStr, conn);
}

/// <summary>
/// 创建一个带密码的数据库
/// </summary>
/// <param name="dbPath"></param>
/// <param name="secretKey"></param>
public DbHelper(string dbPath, string secretKey)
public DbHelper(string dbPath, string? secretKey)
{
connStr = new SqliteConnectionStringBuilder
{
Expand All @@ -59,10 +42,11 @@ public DbHelper(string dbPath, string secretKey)
return;
}
}

var dataProcessor = new DataProcessor(connStr);
dataProcessor.InitializeDatabase();
conn = new SqliteConnection(connStr);
// conn.SetPassword(secretKey);
database.Add(connStr, conn);

}

/// <summary>
Expand Down
Loading