You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
359 lines
11 KiB
359 lines
11 KiB
using Apewer.Internals;
|
|
|
|
#if NETFRAMEWORK
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.Data.OleDb;
|
|
using System.IO;
|
|
using System.Text;
|
|
#endif
|
|
|
|
namespace Apewer.Source
|
|
{
|
|
|
|
/// <summary>用于快速连接 Microsoft Access 数据库的辅助。</summary>
|
|
public partial class Access
|
|
{
|
|
|
|
/// <summary>尝试解析 Access 文件的密码。</summary>
|
|
/// <remarks>当操作系统启用随机化内存分配时,此方法可能会产生异常。</remarks>
|
|
public static string[] ParsePassword(string path) => AccessHelper.GetPassword(path);
|
|
|
|
}
|
|
|
|
#if NETFRAMEWORK
|
|
|
|
public partial class Access : IDbClientBase, IDbClientAdo, IDisposable
|
|
{
|
|
|
|
#region 连接
|
|
|
|
string _connstr = null;
|
|
OleDbConnection _connection = null;
|
|
Timeout _timeout = null;
|
|
|
|
/// <summary>获取或设置日志记录。</summary>
|
|
public Logger Logger { get; set; }
|
|
|
|
/// <summary>获取或设置超时。</summary>
|
|
public Timeout Timeout { get => _timeout; }
|
|
|
|
/// <summary>构造函数。</summary>
|
|
public Access(string connectrionString, Timeout timeout)
|
|
{
|
|
_connstr = connectrionString;
|
|
_timeout = timeout ?? Timeout.Default;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 连接
|
|
|
|
/// <summary>获取当前的 OldDbConnection 对象。</summary>
|
|
public IDbConnection Connection { get => _connection; }
|
|
|
|
/// <summary>数据库是否已经连接。</summary>
|
|
public bool Online
|
|
{
|
|
get
|
|
{
|
|
if (_connection != null)
|
|
{
|
|
if (_connection.State == ConnectionState.Open) return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>连接数据库,若未连接则尝试连接。</summary>
|
|
/// <returns>错误信息。</returns>
|
|
public string Connect()
|
|
{
|
|
if (_connection == null)
|
|
{
|
|
_connection = new OleDbConnection();
|
|
_connection.ConnectionString = _connstr;
|
|
}
|
|
else
|
|
{
|
|
if (_connection.State == ConnectionState.Open) return null;
|
|
}
|
|
try
|
|
{
|
|
_connection.Open();
|
|
if (_connection.State == ConnectionState.Open) return null;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.Error(nameof(Access), "Connect", ex, _connstr);
|
|
Close();
|
|
return ex.Message;
|
|
}
|
|
return "连接失败。";
|
|
}
|
|
|
|
/// <summary>释放对象所占用的系统资源。</summary>
|
|
public void Close()
|
|
{
|
|
if (_connection != null)
|
|
{
|
|
if (_transaction != null)
|
|
{
|
|
if (_autocommit) Commit();
|
|
else Rollback();
|
|
}
|
|
_connection.Close();
|
|
_connection.Dispose();
|
|
_connection = null;
|
|
}
|
|
}
|
|
|
|
/// <summary>释放资源。</summary>
|
|
public void Dispose() => Close();
|
|
|
|
#endregion
|
|
|
|
#region Transaction
|
|
|
|
private IDbTransaction _transaction = null;
|
|
private bool _autocommit = false;
|
|
|
|
/// <summary>启动事务。</summary>
|
|
public string Begin(bool commit = true) => Begin(commit, null);
|
|
|
|
/// <summary>启动事务。</summary>
|
|
public string Begin(bool commit, Class<IsolationLevel> isolation)
|
|
{
|
|
var connect = Connect();
|
|
if (connect.NotEmpty()) return connect;
|
|
if (_transaction != null) return "存在已启动的事务,无法再次启动。";
|
|
try
|
|
{
|
|
_transaction = isolation ? _connection.BeginTransaction(isolation.Value) : _connection.BeginTransaction();
|
|
_autocommit = commit;
|
|
return null;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.Error(nameof(Access), "Begin", ex.Message());
|
|
return ex.Message();
|
|
}
|
|
}
|
|
|
|
/// <summary>提交事务。</summary>
|
|
public string Commit()
|
|
{
|
|
if (_transaction == null) return "事务不存在。";
|
|
try
|
|
{
|
|
_transaction.Commit();
|
|
RuntimeUtility.Dispose(_transaction);
|
|
_transaction = null;
|
|
return null;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
RuntimeUtility.Dispose(_transaction);
|
|
_transaction = null;
|
|
Logger.Error(nameof(Access), "Commit", ex.Message());
|
|
return ex.Message();
|
|
}
|
|
}
|
|
|
|
/// <summary>从挂起状态回滚事务。</summary>
|
|
public string Rollback()
|
|
{
|
|
if (_transaction == null) return "事务不存在。";
|
|
try
|
|
{
|
|
_transaction.Rollback();
|
|
RuntimeUtility.Dispose(_transaction);
|
|
_transaction = null;
|
|
return null;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
RuntimeUtility.Dispose(_transaction);
|
|
_transaction = null;
|
|
Logger.Error(nameof(Access), "Rollback", ex.Message);
|
|
return ex.Message();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 查询和执行
|
|
|
|
/// <summary>使用 SQL 语句进行查询。</summary>
|
|
public IQuery Query(string sql) => Query(sql, null);
|
|
|
|
/// <summary>使用 SQL 语句进行查询。</summary>
|
|
public IQuery Query(string sql, IEnumerable<IDataParameter> parameters)
|
|
{
|
|
if (sql.IsBlank()) return Example.InvalidQueryStatement;
|
|
|
|
var connected = Connect();
|
|
if (connected.NotEmpty()) return new Query(false, connected);
|
|
|
|
try
|
|
{
|
|
using (var command = new OleDbCommand())
|
|
{
|
|
command.Connection = _connection;
|
|
command.CommandTimeout = Timeout.Query;
|
|
command.CommandText = sql;
|
|
if (parameters != null)
|
|
{
|
|
foreach (var p in parameters)
|
|
{
|
|
if (p != null) command.Parameters.Add(p);
|
|
}
|
|
}
|
|
using (var ds = new DataSet())
|
|
{
|
|
using (var da = new OleDbDataAdapter(sql, _connection))
|
|
{
|
|
var name = "table_" + Guid.NewGuid().ToString("\n");
|
|
da.Fill(ds, name);
|
|
var table = ds.Tables[name];
|
|
return new Query(table);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
Logger.Error(nameof(Access), "Query", exception, sql);
|
|
return new Query(exception);
|
|
}
|
|
}
|
|
|
|
/// <summary>执行 SQL 语句。</summary>
|
|
public IExecute Execute(string sql) => Execute(sql, null);
|
|
|
|
/// <summary>执行 SQL 语句,并加入参数。</summary>
|
|
public IExecute Execute(string sql, IEnumerable<IDataParameter> parameters)
|
|
{
|
|
if (sql.IsBlank()) return Example.InvalidExecuteStatement;
|
|
|
|
var connected = Connect();
|
|
if (connected.NotEmpty()) return new Execute(false, connected);
|
|
|
|
var inTransaction = _transaction != null;
|
|
if (!inTransaction) Begin();
|
|
try
|
|
{
|
|
using (var command = new OleDbCommand())
|
|
{
|
|
command.Connection = _connection;
|
|
command.Transaction = (OleDbTransaction)_transaction;
|
|
command.CommandTimeout = Timeout.Execute;
|
|
command.CommandText = sql;
|
|
if (parameters != null)
|
|
{
|
|
foreach (var parameter in parameters)
|
|
{
|
|
if (parameter == null) continue;
|
|
command.Parameters.Add(parameter);
|
|
}
|
|
}
|
|
var rows = command.ExecuteNonQuery();
|
|
if (!inTransaction) Commit(); // todo 此处应该检查事务提交产生的错误。
|
|
return new Execute(true, rows);
|
|
}
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
Logger.Error(nameof(Access), "Execute", exception, sql);
|
|
if (!inTransaction) Rollback();
|
|
return new Execute(exception);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Parameter
|
|
|
|
/// <summary>创建参数列表。</summary>
|
|
public static List<IDbDataParameter> NewParameterList()
|
|
{
|
|
return new List<IDbDataParameter>();
|
|
}
|
|
|
|
/// <summary>创建参数。</summary>
|
|
public static IDbDataParameter CreateParameter(String field, DbType type, Int32 size, Object value)
|
|
{
|
|
var p = new OleDbParameter();
|
|
p.ParameterName = field;
|
|
p.DbType = type;
|
|
p.Size = size;
|
|
p.Value = value;
|
|
return p;
|
|
}
|
|
|
|
/// <summary>创建参数。</summary>
|
|
public static IDbDataParameter CreateParameter(String field, DbType type, Object value)
|
|
{
|
|
var p = new OleDbParameter();
|
|
p.ParameterName = field;
|
|
p.DbType = type;
|
|
p.Value = value;
|
|
return p;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region protected
|
|
|
|
/// <summary>获取或设置连接字符串。</summary>
|
|
internal protected static string GenerateCS(string provider, string path, string pass, string jo)
|
|
{
|
|
if (!File.Exists(path)) return null;
|
|
|
|
var sb = new StringBuilder();
|
|
|
|
sb.Append("provider=", provider, "; ");
|
|
|
|
if (!string.IsNullOrEmpty(path)) sb.Append("data source=", path, "; ");
|
|
|
|
if (string.IsNullOrEmpty(pass)) sb.Append("persist security info=false; ");
|
|
else sb.Append("jet oledb:database password=\"", pass, "\"; ");
|
|
|
|
// Microsoft Access Workgroup Information
|
|
if (!string.IsNullOrEmpty(jo)) sb.Append("jet oledb:system database=", jo, "; ");
|
|
|
|
return sb.ToString();
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
/// <summary>使用 Microsoft.Jet.OLEDB.4.0 访问 Access 97 - 2003 数据库文件。</summary>
|
|
public class AccessJet4 : Access
|
|
{
|
|
|
|
const string JetOleDB4 = "microsoft.jet.oledb.4.0";
|
|
|
|
/// <summary>创建 Access 类的新实例。</summary>
|
|
public AccessJet4(string path, string pass = null, string jo = null, Timeout timeout = null)
|
|
: base(GenerateCS(JetOleDB4, path, pass, jo), timeout) { }
|
|
|
|
}
|
|
|
|
/// <summary>使用 Microsoft.ACE.OLEDB.12.0 访问 Access 2007 数据库文件。</summary>
|
|
public class AccessAce12 : Access
|
|
{
|
|
|
|
const string AceOleDB12 = "microsoft.ace.oledb.12.0";
|
|
|
|
/// <summary>创建 Access 类的新实例。</summary>
|
|
public AccessAce12(string path, string pass = null, string jo = null, Timeout timeout = null)
|
|
: base(GenerateCS(AceOleDB12, path, pass, jo), timeout) { }
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|