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.

317 lines
9.7 KiB

  1. using Apewer.Internals;
  2. #if NETFX
  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 NETFX
  20. public partial class Access : IDatabase, IDisposable
  21. {
  22. /// <summary>创建 Access 类的新实例。</summary>
  23. public static Access Jet4() => new Access(AccessHelper.JetOleDB4);
  24. /// <summary>创建 Access 类的新实例。</summary>
  25. public static Access Ace12() => new Access(AccessHelper.AceOleDB12);
  26. #region 属性、构造函数和 Dispose。
  27. private OleDbConnection _connection = null;
  28. internal string Provider { get; set; }
  29. /// <summary>构造函数。</summary>
  30. internal Access(string provider)
  31. {
  32. Provider = provider;
  33. Timeout = new Timeout();
  34. }
  35. /// <summary>释放资源。</summary>
  36. public void Dispose() => Close();
  37. #endregion
  38. #region 日志。
  39. /// <summary>获取或设置日志记录。</summary>
  40. public Logger Logger { get; set; }
  41. private void LogError(string action, Exception ex, string addtion)
  42. {
  43. var logger = Logger;
  44. if (logger != null) logger.Error(this, "Access", action, ex.GetType().FullName, ex.Message, addtion);
  45. }
  46. #endregion
  47. #region 连接。
  48. /// <summary>获取或设置数据库文件的路径。</summary>
  49. public string Path { get; set; }
  50. /// <summary>Microsoft Access System Database。</summary>
  51. public string Josd { get; set; }
  52. /// <summary>获取或设置用于连接数据库的密码。</summary>
  53. public string Pass { get; set; }
  54. /// <summary>获取或设置超时。</summary>
  55. public Timeout Timeout { get; set; }
  56. /// <summary>数据库是否已经连接。</summary>
  57. public bool Online
  58. {
  59. get
  60. {
  61. if (_connection != null)
  62. {
  63. if (_connection.State == ConnectionState.Open) return true;
  64. }
  65. return false;
  66. }
  67. }
  68. /// <summary>连接数据库,若未连接则尝试连接。</summary>
  69. /// <returns>是否已连接。</returns>
  70. public bool Connect()
  71. {
  72. var cs = GenerateConnectionString();
  73. if (_connection == null)
  74. {
  75. _connection = new OleDbConnection();
  76. _connection.ConnectionString = cs;
  77. }
  78. else
  79. {
  80. if (_connection.State == ConnectionState.Open) return true;
  81. }
  82. try
  83. {
  84. _connection.Open();
  85. if (_connection.State == ConnectionState.Open) return true;
  86. }
  87. catch (Exception argException)
  88. {
  89. LogError("Connect", argException, cs);
  90. Close();
  91. }
  92. return false;
  93. }
  94. /// <summary>释放对象所占用的系统资源。</summary>
  95. public void Close()
  96. {
  97. if (_connection != null)
  98. {
  99. _connection.Close();
  100. _connection.Dispose();
  101. _connection = null;
  102. }
  103. }
  104. /// <summary>获取或设置连接字符串。</summary>
  105. private string GenerateConnectionString()
  106. {
  107. if (!File.Exists(Path)) return null;
  108. var sb = new StringBuilder();
  109. sb.Append("provider=", Provider, "; ");
  110. if (!string.IsNullOrEmpty(Path)) sb.Append("data source=", Path, "; ");
  111. if (string.IsNullOrEmpty(Pass)) sb.Append("persist security info=false; ");
  112. else sb.Append("jet oledb:database password=\"", Pass, "\"; ");
  113. // Microsoft Access Workgroup Information
  114. if (!string.IsNullOrEmpty(Josd)) sb.Append("jet oledb:system database=", Josd, "; ");
  115. return sb.ToString();
  116. }
  117. #endregion
  118. #region 查询和执行。
  119. /// <summary>使用 SQL 语句进行查询。</summary>
  120. public IQuery Query(string sql) => Query(sql, null);
  121. /// <summary>使用 SQL 语句进行查询。</summary>
  122. public IQuery Query(string sql, IEnumerable<IDataParameter> parameters)
  123. {
  124. if (sql.IsBlank()) return Example.InvalidQueryStatement;
  125. const string table = "queryresult";
  126. var connected = Connect();
  127. if (!connected) return Example.InvalidQueryConnection;
  128. var query = new Query();
  129. try
  130. {
  131. var command = new OleDbCommand();
  132. command.Connection = _connection;
  133. command.CommandTimeout = Timeout.Query;
  134. command.CommandText = sql;
  135. if (parameters != null)
  136. {
  137. foreach (var p in parameters)
  138. {
  139. if (p != null) command.Parameters.Add(p);
  140. }
  141. }
  142. using (var ds = new DataSet())
  143. {
  144. using (var da = new OleDbDataAdapter(sql, _connection))
  145. {
  146. da.Fill(ds, table);
  147. query.Table = ds.Tables[table];
  148. }
  149. }
  150. command.Dispose();
  151. query.Success = true;
  152. }
  153. catch (Exception exception)
  154. {
  155. LogError("Query", exception, sql);
  156. query.Success = false;
  157. query.Exception = exception;
  158. }
  159. return query;
  160. }
  161. /// <summary>执行 SQL 语句。</summary>
  162. public IExecute Execute(string sql) => Execute(sql, null);
  163. /// <summary>执行 SQL 语句,并加入参数。</summary>
  164. public IExecute Execute(string sql, IEnumerable<IDataParameter> parameters)
  165. {
  166. if (sql.IsBlank()) return Example.InvalidExecuteStatement;
  167. var connected = Connect();
  168. if (!connected) return Example.InvalidExecuteConnection;
  169. var execute = new Execute();
  170. using (var transaction = _connection.BeginTransaction())
  171. {
  172. try
  173. {
  174. using (var command = new OleDbCommand())
  175. {
  176. command.Connection = _connection;
  177. command.Transaction = transaction;
  178. command.CommandTimeout = Timeout.Execute;
  179. command.CommandText = sql;
  180. if (parameters != null)
  181. {
  182. foreach (var parameter in parameters)
  183. {
  184. if (parameter == null) continue;
  185. command.Parameters.Add(parameter);
  186. }
  187. }
  188. execute.Rows += command.ExecuteNonQuery();
  189. transaction.Commit();
  190. }
  191. execute.Success = true;
  192. }
  193. catch (Exception exception)
  194. {
  195. LogError("Execute", exception, sql);
  196. try { transaction.Rollback(); } catch { }
  197. execute.Success = false;
  198. execute.Exception = exception;
  199. }
  200. }
  201. return execute;
  202. }
  203. #endregion
  204. #region Parameter
  205. /// <summary>创建参数列表。</summary>
  206. public static List<IDbDataParameter> NewParameterList()
  207. {
  208. return new List<IDbDataParameter>();
  209. }
  210. /// <summary>创建参数。</summary>
  211. public static IDbDataParameter CreateParameter(String field, DbType type, Int32 size, Object value)
  212. {
  213. var p = new OleDbParameter();
  214. p.ParameterName = field;
  215. p.DbType = type;
  216. p.Size = size;
  217. p.Value = value;
  218. return p;
  219. }
  220. /// <summary>创建参数。</summary>
  221. public static IDbDataParameter CreateParameter(String field, DbType type, Object value)
  222. {
  223. var p = new OleDbParameter();
  224. p.ParameterName = field;
  225. p.DbType = type;
  226. p.Value = value;
  227. return p;
  228. }
  229. #endregion
  230. }
  231. /// <summary>使用 Microsoft.Jet.OLEDB.4.0 访问 Access 97 - 2003 数据库文件。</summary>
  232. public class AccessJet4 : Access
  233. {
  234. /// <summary>创建 Access 类的新实例。</summary>
  235. public AccessJet4() : base(AccessHelper.JetOleDB4) { }
  236. /// <summary>创建 Access 类的新实例。</summary>
  237. public AccessJet4(string path) : base(AccessHelper.JetOleDB4)
  238. {
  239. Path = path;
  240. }
  241. }
  242. /// <summary>使用 Microsoft.ACE.OLEDB.12.0 访问 Access 2007 数据库文件。</summary>
  243. public class AccessAce12 : Access
  244. {
  245. /// <summary>创建 Access 类的新实例。</summary>
  246. public AccessAce12() : base(AccessHelper.AceOleDB12) { }
  247. /// <summary>创建 Access 类的新实例。</summary>
  248. public AccessAce12(string path) : base(AccessHelper.AceOleDB12)
  249. {
  250. Path = path;
  251. }
  252. }
  253. #endif
  254. }