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

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. using Apewer.Internals;
  2. #if NETFRAMEWORK
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Data;
  6. using System.Data.OleDb;
  7. using System.IO;
  8. using System.Text;
  9. #endif
  10. namespace Apewer.Source
  11. {
  12. /// <summary>用于快速连接 Microsoft Access 数据库的辅助。</summary>
  13. public partial class Access
  14. {
  15. /// <summary>尝试解析 Access 文件的密码。</summary>
  16. /// <remarks>当操作系统启用随机化内存分配时,此方法可能会产生异常。</remarks>
  17. public static string[] ParsePassword(string path) => AccessHelper.GetPassword(path);
  18. }
  19. #if NETFRAMEWORK
  20. public partial class Access : IDbClientBase, IDbClientAdo, IDisposable
  21. {
  22. #region 连接
  23. string _connstr = null;
  24. OleDbConnection _connection = null;
  25. Timeout _timeout = null;
  26. /// <summary>获取或设置日志记录。</summary>
  27. public Logger Logger { get; set; }
  28. /// <summary>获取或设置超时。</summary>
  29. public Timeout Timeout { get => _timeout; }
  30. /// <summary>构造函数。</summary>
  31. public Access(string connectrionString, Timeout timeout)
  32. {
  33. _connstr = connectrionString;
  34. _timeout = timeout ?? Timeout.Default;
  35. }
  36. #endregion
  37. #region 连接
  38. /// <summary>获取当前的 OldDbConnection 对象。</summary>
  39. public IDbConnection Connection { get => _connection; }
  40. /// <summary>数据库是否已经连接。</summary>
  41. public bool Online
  42. {
  43. get
  44. {
  45. if (_connection != null)
  46. {
  47. if (_connection.State == ConnectionState.Open) return true;
  48. }
  49. return false;
  50. }
  51. }
  52. /// <summary>连接数据库,若未连接则尝试连接。</summary>
  53. /// <returns>错误信息。</returns>
  54. public string Connect()
  55. {
  56. if (_connection == null)
  57. {
  58. _connection = new OleDbConnection();
  59. _connection.ConnectionString = _connstr;
  60. }
  61. else
  62. {
  63. if (_connection.State == ConnectionState.Open) return null;
  64. }
  65. try
  66. {
  67. _connection.Open();
  68. if (_connection.State == ConnectionState.Open) return null;
  69. }
  70. catch (Exception ex)
  71. {
  72. Logger.Error(nameof(Access), "Connect", ex, _connstr);
  73. Close();
  74. return ex.Message;
  75. }
  76. return "连接失败。";
  77. }
  78. /// <summary>释放对象所占用的系统资源。</summary>
  79. public void Close()
  80. {
  81. if (_connection != null)
  82. {
  83. if (_transaction != null)
  84. {
  85. if (_autocommit) Commit();
  86. else Rollback();
  87. }
  88. _connection.Close();
  89. _connection.Dispose();
  90. _connection = null;
  91. }
  92. }
  93. /// <summary>释放资源。</summary>
  94. public void Dispose() => Close();
  95. #endregion
  96. #region Transaction
  97. private IDbTransaction _transaction = null;
  98. private bool _autocommit = false;
  99. /// <summary>启动事务。</summary>
  100. public string Begin(bool commit = true) => Begin(commit, null);
  101. /// <summary>启动事务。</summary>
  102. public string Begin(bool commit, Class<IsolationLevel> isolation)
  103. {
  104. var connect = Connect();
  105. if (connect.NotEmpty()) return connect;
  106. if (_transaction != null) return "存在已启动的事务,无法再次启动。";
  107. try
  108. {
  109. _transaction = isolation ? _connection.BeginTransaction(isolation.Value) : _connection.BeginTransaction();
  110. _autocommit = commit;
  111. return null;
  112. }
  113. catch (Exception ex)
  114. {
  115. Logger.Error(nameof(Access), "Begin", ex.Message());
  116. return ex.Message();
  117. }
  118. }
  119. /// <summary>提交事务。</summary>
  120. public string Commit()
  121. {
  122. if (_transaction == null) return "事务不存在。";
  123. try
  124. {
  125. _transaction.Commit();
  126. RuntimeUtility.Dispose(_transaction);
  127. _transaction = null;
  128. return null;
  129. }
  130. catch (Exception ex)
  131. {
  132. RuntimeUtility.Dispose(_transaction);
  133. _transaction = null;
  134. Logger.Error(nameof(Access), "Commit", ex.Message());
  135. return ex.Message();
  136. }
  137. }
  138. /// <summary>从挂起状态回滚事务。</summary>
  139. public string Rollback()
  140. {
  141. if (_transaction == null) return "事务不存在。";
  142. try
  143. {
  144. _transaction.Rollback();
  145. RuntimeUtility.Dispose(_transaction);
  146. _transaction = null;
  147. return null;
  148. }
  149. catch (Exception ex)
  150. {
  151. RuntimeUtility.Dispose(_transaction);
  152. _transaction = null;
  153. Logger.Error(nameof(Access), "Rollback", ex.Message);
  154. return ex.Message();
  155. }
  156. }
  157. #endregion
  158. #region 查询和执行
  159. /// <summary>使用 SQL 语句进行查询。</summary>
  160. public IQuery Query(string sql) => Query(sql, null);
  161. /// <summary>使用 SQL 语句进行查询。</summary>
  162. public IQuery Query(string sql, IEnumerable<IDataParameter> parameters)
  163. {
  164. if (sql.IsBlank()) return Example.InvalidQueryStatement;
  165. var connected = Connect();
  166. if (connected.NotEmpty()) return new Query(false, connected);
  167. try
  168. {
  169. using (var command = new OleDbCommand())
  170. {
  171. command.Connection = _connection;
  172. command.CommandTimeout = Timeout.Query;
  173. command.CommandText = sql;
  174. if (parameters != null)
  175. {
  176. foreach (var p in parameters)
  177. {
  178. if (p != null) command.Parameters.Add(p);
  179. }
  180. }
  181. using (var ds = new DataSet())
  182. {
  183. using (var da = new OleDbDataAdapter(sql, _connection))
  184. {
  185. var name = "table_" + Guid.NewGuid().ToString("n");
  186. da.Fill(ds, name);
  187. var table = ds.Tables[name];
  188. return new Query(table);
  189. }
  190. }
  191. }
  192. }
  193. catch (Exception exception)
  194. {
  195. Logger.Error(nameof(Access), "Query", exception, sql);
  196. return new Query(exception);
  197. }
  198. }
  199. /// <summary>执行 SQL 语句。</summary>
  200. public IExecute Execute(string sql) => Execute(sql, null);
  201. /// <summary>执行 SQL 语句,并加入参数。</summary>
  202. public IExecute Execute(string sql, IEnumerable<IDataParameter> parameters)
  203. {
  204. if (sql.IsBlank()) return Example.InvalidExecuteStatement;
  205. var connected = Connect();
  206. if (connected.NotEmpty()) return new Execute(false, connected);
  207. var inTransaction = _transaction != null;
  208. if (!inTransaction) Begin();
  209. try
  210. {
  211. using (var command = new OleDbCommand())
  212. {
  213. command.Connection = _connection;
  214. command.Transaction = (OleDbTransaction)_transaction;
  215. command.CommandTimeout = Timeout.Execute;
  216. command.CommandText = sql;
  217. if (parameters != null)
  218. {
  219. foreach (var parameter in parameters)
  220. {
  221. if (parameter == null) continue;
  222. command.Parameters.Add(parameter);
  223. }
  224. }
  225. var rows = command.ExecuteNonQuery();
  226. if (!inTransaction) Commit(); // todo 此处应该检查事务提交产生的错误。
  227. return new Execute(true, rows);
  228. }
  229. }
  230. catch (Exception exception)
  231. {
  232. Logger.Error(nameof(Access), "Execute", exception, sql);
  233. if (!inTransaction) Rollback();
  234. return new Execute(exception);
  235. }
  236. }
  237. #endregion
  238. #region Parameter
  239. /// <summary>创建参数列表。</summary>
  240. public static List<IDbDataParameter> NewParameterList()
  241. {
  242. return new List<IDbDataParameter>();
  243. }
  244. /// <summary>创建参数。</summary>
  245. public static IDbDataParameter CreateParameter(String field, DbType type, Int32 size, Object value)
  246. {
  247. var p = new OleDbParameter();
  248. p.ParameterName = field;
  249. p.DbType = type;
  250. p.Size = size;
  251. p.Value = value;
  252. return p;
  253. }
  254. /// <summary>创建参数。</summary>
  255. public static IDbDataParameter CreateParameter(String field, DbType type, Object value)
  256. {
  257. var p = new OleDbParameter();
  258. p.ParameterName = field;
  259. p.DbType = type;
  260. p.Value = value;
  261. return p;
  262. }
  263. #endregion
  264. #region protected
  265. /// <summary>获取或设置连接字符串。</summary>
  266. internal protected static string GenerateCS(string provider, string path, string pass, string jo)
  267. {
  268. if (!File.Exists(path)) return null;
  269. var sb = new StringBuilder();
  270. sb.Append("provider=", provider, "; ");
  271. if (!string.IsNullOrEmpty(path)) sb.Append("data source=", path, "; ");
  272. if (string.IsNullOrEmpty(pass)) sb.Append("persist security info=false; ");
  273. else sb.Append("jet oledb:database password=\"", pass, "\"; ");
  274. // Microsoft Access Workgroup Information
  275. if (!string.IsNullOrEmpty(jo)) sb.Append("jet oledb:system database=", jo, "; ");
  276. return sb.ToString();
  277. }
  278. #endregion
  279. }
  280. /// <summary>使用 Microsoft.Jet.OLEDB.4.0 访问 Access 97 - 2003 数据库文件。</summary>
  281. public class AccessJet4 : Access
  282. {
  283. const string JetOleDB4 = "microsoft.jet.oledb.4.0";
  284. /// <summary>创建 Access 类的新实例。</summary>
  285. public AccessJet4(string path, string pass = null, string jo = null, Timeout timeout = null)
  286. : base(GenerateCS(JetOleDB4, path, pass, jo), timeout) { }
  287. }
  288. /// <summary>使用 Microsoft.ACE.OLEDB.12.0 访问 Access 2007 数据库文件。</summary>
  289. public class AccessAce12 : Access
  290. {
  291. const string AceOleDB12 = "microsoft.ace.oledb.12.0";
  292. /// <summary>创建 Access 类的新实例。</summary>
  293. public AccessAce12(string path, string pass = null, string jo = null, Timeout timeout = null)
  294. : base(GenerateCS(AceOleDB12, path, pass, jo), timeout) { }
  295. }
  296. #endif
  297. }