using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using System.IO;
using System.Threading.Tasks;
using TeamAAS.Database.Attributes;
using TeamAAS.Database.Interfaces;
using TeamAAS.Database.Models;
namespace TeamAAS.Database.Providers
{
///
/// SQLite 数据库提供者实现
///
[DatabaseProvider("sqlite", DisplayName = "SQLite", RequiresServer = false,
Description = "SQLite 文件型数据库,基于 System.Data.SQLite")]
public class SqliteDatabase : IDatabase
{
private SQLiteConnection _connection;
private DatabaseConfig _config;
private readonly object _sync = new object();
public Guid Id { get; private set; }
public string Name { get; set; }
public string ProviderType => "sqlite";
public bool IsConnected => _connection != null && _connection.State == ConnectionState.Open;
public string ConnectionString
{
get
{
if (_config == null) return string.Empty;
if (!string.IsNullOrWhiteSpace(_config.ConnectionString))
return _config.ConnectionString;
return $"Data Source={GetDbFilePath()};Version=3;";
}
}
private string GetDbFilePath()
{
// SQLite: Server 字段存文件路径,或者 DatabaseName 存文件名
if (!string.IsNullOrWhiteSpace(_config.Server) && _config.Server.Contains("\\"))
return _config.Server;
if (!string.IsNullOrWhiteSpace(_config.DatabaseName) && _config.DatabaseName.Contains("\\"))
return _config.DatabaseName;
var fileName = string.IsNullOrWhiteSpace(_config.DatabaseName)
? _config.Server
: _config.DatabaseName;
if (string.IsNullOrWhiteSpace(fileName))
fileName = "database.db";
if (!Path.IsPathRooted(fileName))
fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
return fileName;
}
private string GetRawConnectionString()
{
if (!string.IsNullOrWhiteSpace(_config?.ConnectionString))
return _config.ConnectionString;
if (_config == null)
throw new InvalidOperationException("数据库未配置");
var filePath = GetDbFilePath();
var builder = new SQLiteConnectionStringBuilder
{
DataSource = filePath,
Version = 3,
FailIfMissing = false,
JournalMode = SQLiteJournalModeEnum.Wal
};
if (_config.ConnectionTimeout > 0)
builder.DefaultTimeout = _config.ConnectionTimeout;
if (_config.ExtraParams != null)
{
foreach (var kv in _config.ExtraParams)
{
try
{
var prop = typeof(SQLiteConnectionStringBuilder).GetProperty(kv.Key);
if (prop != null && prop.CanWrite)
prop.SetValue(builder, Convert.ChangeType(kv.Value, prop.PropertyType));
}
catch { /* 忽略无效参数 */ }
}
}
return builder.ConnectionString;
}
public void Configure(DatabaseConfig config)
{
_config = config ?? throw new ArgumentNullException(nameof(config));
Id = config.Id == Guid.Empty ? Guid.NewGuid() : config.Id;
Name = config.Name ?? $"SQLite_{Path.GetFileName(GetDbFilePath())}";
}
public bool Open()
{
lock (_sync)
{
try
{
if (_connection == null)
{
var filePath = GetDbFilePath();
var dir = Path.GetDirectoryName(filePath);
if (!string.IsNullOrWhiteSpace(dir) && !Directory.Exists(dir))
Directory.CreateDirectory(dir);
_connection = new SQLiteConnection(GetRawConnectionString());
}
if (_connection.State == ConnectionState.Open)
return true;
_connection.Open();
return true;
}
catch
{
return false;
}
}
}
public Task OpenAsync()
{
return Task.Run(() => Open());
}
public void Close()
{
lock (_sync)
{
if (_connection != null)
{
try { _connection.Close(); } catch { }
}
}
}
public Task CloseAsync()
{
return Task.Run(() => Close());
}
public (bool Success, string Message) TestConnection()
{
try
{
using (var conn = new SQLiteConnection(GetRawConnectionString()))
{
conn.Open();
return (true, "连接成功");
}
}
catch (Exception ex)
{
return (false, ex.Message);
}
}
public Task<(bool Success, string Message)> TestConnectionAsync()
{
return Task.Run(() => TestConnection());
}
public int ExecuteNonQuery(string sql, IDictionary parameters = null)
{
using (var cmd = CreateCommand(sql, parameters))
{
EnsureOpen();
return cmd.ExecuteNonQuery();
}
}
public Task ExecuteNonQueryAsync(string sql, IDictionary parameters = null)
{
return Task.Run(() => ExecuteNonQuery(sql, parameters));
}
public DataTable ExecuteQuery(string sql, IDictionary parameters = null)
{
using (var cmd = CreateCommand(sql, parameters))
{
EnsureOpen();
var dt = new DataTable();
using (var reader = cmd.ExecuteReader())
{
dt.Load(reader);
}
return dt;
}
}
public Task ExecuteQueryAsync(string sql, IDictionary parameters = null)
{
return Task.Run(() => ExecuteQuery(sql, parameters));
}
public object ExecuteScalar(string sql, IDictionary parameters = null)
{
using (var cmd = CreateCommand(sql, parameters))
{
EnsureOpen();
return cmd.ExecuteScalar();
}
}
public Task