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.

965 lines
35 KiB

4 years ago
  1. #if EXTRA
  2. /* 2021.08.03 */
  3. using Apewer;
  4. using Apewer.Source;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Data;
  8. using System.Data.SQLite;
  9. using System.Text;
  10. using System.Data.Common;
  11. //using Mono.Data.Sqlite;
  12. namespace Apewer.Source
  13. {
  14. /// <summary>用于快速连接 SQLite 数据库的辅助。</summary>
  15. public class Sqlite : IDatabase, IOrm, IDisposable
  16. {
  17. #region 变量定义。
  18. private SQLiteConnection _db = null;
  19. private Timeout _timeout = new Timeout();
  20. private string _connstring = "";
  21. private string _path = "";
  22. private string _pass = "";
  23. private byte[] _passdata = BinaryUtility.EmptyBytes;
  24. #endregion
  25. #region this
  26. private void VarInit(string path, Timeout timeout, string pass, byte[] passData)
  27. {
  28. _path = (path == null) ? "" : path;
  29. _passdata = (passData == null) ? BinaryUtility.EmptyBytes : passData;
  30. _pass = (pass == null) ? "" : pass;
  31. _timeout = timeout;
  32. }
  33. /// <summary>连接内存。</summary>
  34. public Sqlite() => VarInit(Memory, new Timeout(), null, null);
  35. /// <summary>连接指定文件。</summary>
  36. public Sqlite(string path) => VarInit(path, new Timeout(), null, null);
  37. /// <summary>连接指定文件。</summary>
  38. private Sqlite(string path, byte[] passData) => VarInit(path, new Timeout(), null, passData);
  39. /// <summary>连接指定文件。</summary>
  40. public Sqlite(string path, string pass) => VarInit(path, new Timeout(), pass, null);
  41. /// <summary>连接指定文件。</summary>
  42. public Sqlite(string path, Timeout timeout) => VarInit(path, timeout, null, null);
  43. /// <summary>连接指定文件。</summary>
  44. private Sqlite(string path, Timeout timeout, byte[] pass) => VarInit(path, timeout, null, pass);
  45. /// <summary>连接指定文件。</summary>
  46. public Sqlite(string path, Timeout timeout, string pass) => VarInit(path, timeout, pass, null);
  47. #endregion
  48. #region 日志。
  49. /// <summary>获取或设置日志记录。</summary>
  50. public Logger Logger { get; set; }
  51. private void LogError(string action, Exception ex, string addtion)
  52. {
  53. var logger = Logger;
  54. if (logger != null) logger.Error(this, "SQLite", action, ex.GetType().FullName, ex.Message, addtion);
  55. }
  56. private void LogError(string action, string message)
  57. {
  58. var logger = Logger;
  59. if (logger != null) logger.Error(this, "SQLite", action, message);
  60. }
  61. #endregion
  62. #region 实现接口。
  63. /// <summary>数据库是否已经连接。</summary>
  64. public bool Online { get => _db != null && _db.State == ConnectionState.Open; }
  65. /// <summary>连接数据库,若未连接则尝试连接。</summary>
  66. /// <returns>是否已连接。</returns>
  67. public bool Connect()
  68. {
  69. if (_db == null)
  70. {
  71. _db = new SQLiteConnection();
  72. _db.ConnectionString = ConnectionString;
  73. //if (string.IsNullOrEmpty(_connstring) && string.IsNullOrEmpty(_pass) && (_passdata.Length > 0))
  74. //{
  75. // _db.SetPassword(_pass);
  76. //}
  77. }
  78. else
  79. {
  80. if (_db.State == ConnectionState.Open) return true;
  81. }
  82. try
  83. {
  84. _db.Open();
  85. switch (_db.State)
  86. {
  87. case ConnectionState.Open: return true;
  88. default: return false;
  89. }
  90. }
  91. catch (Exception ex)
  92. {
  93. LogError("Connection", ex, _db.ConnectionString);
  94. Close();
  95. return false;
  96. }
  97. }
  98. /// <summary>关闭连接,并释放对象所占用的系统资源。</summary>
  99. public void Close()
  100. {
  101. if (_db != null)
  102. {
  103. //_db.Close();
  104. _db.Dispose();
  105. _db = null;
  106. }
  107. }
  108. /// <summary>关闭连接,释放对象所占用的系统资源,并清除连接信息。</summary>
  109. public void Dispose() { Close(); }
  110. /// <summary>查询。</summary>
  111. public IQuery Query(string sql) => Query(sql, null);
  112. /// <summary>查询。</summary>
  113. public IQuery Query(string sql, IEnumerable<IDataParameter> parameters)
  114. {
  115. if (string.IsNullOrEmpty(sql)) return Example.InvalidQueryStatement;
  116. const string table = "result";
  117. var connected = Connect();
  118. if (!connected) return Example.InvalidQueryConnection;
  119. var query = new Query();
  120. try
  121. {
  122. var command = new SQLiteCommand();
  123. command.Connection = _db;
  124. command.CommandTimeout = Timeout.Query;
  125. command.CommandText = sql;
  126. if (parameters != null)
  127. {
  128. foreach (var p in parameters)
  129. {
  130. if (p != null) command.Parameters.Add(p);
  131. }
  132. }
  133. using (var dataset = new DataSet())
  134. {
  135. using (var da = new SQLiteDataAdapter(sql, _db))
  136. {
  137. da.Fill(dataset, table);
  138. query.Table = dataset.Tables[table];
  139. }
  140. }
  141. command.Dispose();
  142. query.Success = true;
  143. }
  144. catch (Exception ex)
  145. {
  146. LogError("Query", ex, sql);
  147. query.Success = false;
  148. query.Exception = ex;
  149. }
  150. return query;
  151. }
  152. /// <summary>执行单条 Transact-SQL 语句。</summary>
  153. public IExecute Execute(string sql) => Execute(sql, null);
  154. /// <summary>执行单条 Transact-SQL 语句,并加入参数。</summary>
  155. public IExecute Execute(string sql, IEnumerable<IDataParameter> parameters)
  156. {
  157. if (string.IsNullOrEmpty(sql)) return Example.InvalidExecuteStatement;
  158. var connected = Connect();
  159. if (!connected) return Example.InvalidExecuteConnection;
  160. var transaction = _db.BeginTransaction();
  161. var execute = new Execute();
  162. try
  163. {
  164. var command = new SQLiteCommand();
  165. command.Connection = _db;
  166. command.Transaction = transaction;
  167. command.CommandTimeout = Timeout.Execute;
  168. command.CommandText = sql;
  169. if (parameters != null)
  170. {
  171. foreach (var p in parameters)
  172. {
  173. if (p != null) command.Parameters.Add(p);
  174. }
  175. }
  176. execute.Rows += command.ExecuteNonQuery();
  177. transaction.Commit();
  178. command.Dispose();
  179. execute.Success = true;
  180. }
  181. catch (Exception ex)
  182. {
  183. try { transaction.Rollback(); } catch { }
  184. LogError("Execute", ex, sql);
  185. execute.Success = false;
  186. execute.Exception = ex;
  187. }
  188. try { transaction.Dispose(); } catch { }
  189. return execute;
  190. }
  191. #endregion
  192. #region 属性。
  193. /// <summary>获取当前的 SQLiteConnection 对象。</summary>
  194. public IDbConnection Connection { get => _db; }
  195. /// <summary>获取或设置超时。</summary>
  196. public Timeout Timeout { get => _timeout; set => _timeout = value; }
  197. /// <summary>获取或设置连接字符串,连接字符串非空时将忽略 Path 属性。数据库在线时无法设置。</summary>
  198. public string ConnectionString
  199. {
  200. get
  201. {
  202. if (string.IsNullOrEmpty(_connstring))
  203. {
  204. var temp = new StringBuilder();
  205. temp.Append("data source='", _path, "'; version=3; ");
  206. if (!string.IsNullOrEmpty(_pass)) temp.Append("password=", _pass, "; ");
  207. return temp.ToString();
  208. }
  209. else return _connstring;
  210. }
  211. set
  212. {
  213. if (Online) return;
  214. _connstring = string.IsNullOrEmpty(value) ? "" : value;
  215. }
  216. }
  217. /// <summary>获取或设置数据库路径(文件或内存)。数据库在线时无法设置。</summary>
  218. public string Path
  219. {
  220. get { return _path; }
  221. set
  222. {
  223. if (Online) return;
  224. _path = string.IsNullOrEmpty(value) ? "" : value;
  225. }
  226. }
  227. /// <summary>获取或设置数据库密码。数据库在线时无法设置。</summary>
  228. public string Password
  229. {
  230. get { return _pass; }
  231. set
  232. {
  233. if (Online) return;
  234. _pass = string.IsNullOrEmpty(value) ? "" : value;
  235. }
  236. }
  237. /// <summary>获取或设置数据库密码。数据库在线时无法设置。</summary>
  238. private byte[] PasswordData
  239. {
  240. get { return _passdata; }
  241. set
  242. {
  243. if (Online) return;
  244. _passdata = (value == null) ? BinaryUtility.EmptyBytes : value;
  245. }
  246. }
  247. /// <summary>保存当前数据库到文件,若文件已存在则将重写文件。</summary>
  248. public bool Save(string path)
  249. {
  250. if (!StorageUtility.CreateFile(path, 0, true))
  251. {
  252. LogError("Save", TextUtility.Merge("创建文件 ", path, " 失败。"));
  253. return false;
  254. }
  255. var temp = new Sqlite(path);
  256. var result = Save(temp);
  257. temp.Close();
  258. return result;
  259. }
  260. /// <summary>保存当前数据库到文件,若文件已存在则将重写文件。</summary>
  261. public bool Save(string path, string password)
  262. {
  263. if (!StorageUtility.CreateFile(path, 0, true))
  264. {
  265. LogError("Save", TextUtility.Merge("创建文件 ", path, " 失败。"));
  266. return false;
  267. }
  268. var temp = new Sqlite(path, password);
  269. var result = Save(temp);
  270. temp.Close();
  271. return result;
  272. }
  273. /// <summary>保存当前数据库到目标数据库。</summary>
  274. public bool Save(Sqlite destination)
  275. {
  276. var error = Backup(this, destination);
  277. return string.IsNullOrEmpty(error);
  278. }
  279. /// <summary>加载文件到当前数据库。</summary>
  280. public bool Load(string path)
  281. {
  282. var temp = new Sqlite(path);
  283. var result = Load(temp);
  284. temp.Close();
  285. return result;
  286. }
  287. /// <summary>加载文件到当前数据库。</summary>
  288. public bool Load(string path, params byte[] pass)
  289. {
  290. var temp = new Sqlite(path, pass);
  291. var result = Load(temp);
  292. temp.Close();
  293. return result;
  294. }
  295. /// <summary>加载文件到当前数据库。</summary>
  296. public bool Load(string path, string pass)
  297. {
  298. var temp = new Sqlite(path, pass);
  299. var result = Load(temp);
  300. temp.Close();
  301. return result;
  302. }
  303. /// <summary>加载源数据库到当前数据库。</summary>
  304. public bool Load(Sqlite source)
  305. {
  306. var error = Backup(source, this);
  307. return string.IsNullOrEmpty(error);
  308. }
  309. #endregion
  310. #region ORM。
  311. /// <summary>查询数据库中的所有表名。</summary>
  312. public List<string> TableNames()
  313. {
  314. var list = new List<string>();
  315. if (Connect())
  316. {
  317. var sql = "select name from sqlite_master where type='table' order by name; ";
  318. var query = (Query)Query(sql);
  319. for (int r = 0; r < query.Rows; r++)
  320. {
  321. var cell = query.Text(r, 0);
  322. if (TextUtility.IsBlank(cell)) continue;
  323. list.Add(cell);
  324. }
  325. query.Dispose();
  326. }
  327. return list;
  328. }
  329. /// <summary>查询数据库中的所有视图名。</summary>
  330. public List<string> ViewNames()
  331. {
  332. var list = new List<string>();
  333. if (Connect())
  334. {
  335. var sql = "select name from sqlite_master where type='view' order by name; ";
  336. var query = (Query)Query(sql);
  337. for (int r = 0; r < query.Rows; r++)
  338. {
  339. var cell = query.Text(r, 0);
  340. if (TextUtility.IsBlank(cell)) continue;
  341. list.Add(cell);
  342. }
  343. query.Dispose();
  344. }
  345. return list;
  346. }
  347. /// <summary>查询表中的所有列名。</summary>
  348. public List<string> ColumnNames(string table)
  349. {
  350. var list = new List<string>();
  351. if (Connect())
  352. {
  353. var t = TextUtility.AntiInject(table);
  354. var sql = TextUtility.Merge("pragma table_info('", TextUtility.AntiInject(t), "'); ");
  355. using (var query = Query(sql) as Query)
  356. {
  357. for (int r = 0; r < query.Rows; r++)
  358. {
  359. var cell = query.Text(r, "name");
  360. if (TextUtility.IsBlank(cell)) continue;
  361. list.Add(cell);
  362. }
  363. }
  364. }
  365. return list;
  366. }
  367. /// <summary>创建表,不修改已存在表。成功时返回空字符串,发生异常时返回异常信息。</summary>
  368. public string Initialize(Record model) => model == null ? "参数无效。" : Initialize(model.GetType());
  369. /// <summary>创建表,不修改已存在表。成功时返回空字符串,发生异常时返回异常信息。</summary>
  370. public string Initialize<T>() where T : Record => Initialize(typeof(T));
  371. /// <summary>创建表,不修改已存在表。当现存表中缺少模型中属性对应的列时增加列。成功时返回空字符串,发生异常时返回异常信息。</summary>
  372. public string Initialize(Type model)
  373. {
  374. var structure = null as TableStructure;
  375. try { structure = TableStructure.ParseModel(model); }
  376. catch (Exception exception) { return exception.Message; }
  377. // 连接数据库。
  378. if (!Connect()) return "连接数据库失败。";
  379. // 检查现存表。
  380. var exists = false;
  381. var tables = TableNames();
  382. if (tables.Count > 0)
  383. {
  384. var lower = structure.Table.ToLower();
  385. foreach (var table in tables)
  386. {
  387. if (TextUtility.IsBlank(table)) continue;
  388. if (table.ToLower() == lower)
  389. {
  390. exists = true;
  391. break;
  392. }
  393. }
  394. }
  395. if (exists)
  396. {
  397. return TextUtility.Merge("指定的表已经存在。");
  398. }
  399. else
  400. {
  401. var sqlcolumns = new List<string>();
  402. foreach (var column in structure.Columns.Values)
  403. {
  404. var type = GetColumnDeclaration(column);
  405. if (type == TextUtility.EmptyString) return TextUtility.Merge("类型 ", column.Type.ToString(), " 不受支持。");
  406. sqlcolumns.Add(type);
  407. }
  408. var sql = TextUtility.Merge("create table [", structure.Table, "](", TextUtility.Join(", ", sqlcolumns), "); ");
  409. var execute = Execute(sql);
  410. if (execute.Success) return TextUtility.EmptyString;
  411. return execute.Error;
  412. }
  413. }
  414. /// <summary>插入记录。成功时候返回空字符串,发生异常时返回异常信息。</summary>
  415. public string Insert(Record record)
  416. {
  417. if (record == null) return "参数无效。";
  418. record.FixProperties();
  419. var structure = null as TableStructure;
  420. try { structure = TableStructure.ParseModel(record); }
  421. catch (Exception exception) { return exception.Message; }
  422. var parameters = structure.CreateDataParameters(record, CreateDataParameter);
  423. var sql = GenerateInsertStatement(structure.Table, (IEnumerable<IDataParameter>)parameters);
  424. var execute = Execute(sql, parameters);
  425. if (execute.Success && execute.Rows > 0) return TextUtility.EmptyString;
  426. return execute.Error;
  427. }
  428. /// <summary>更新记录,实体中的 Created 和 Key 属性不被更新。成功时返回空字符串,发生异常时返回异常信息。</summary>
  429. public string Update(Record record)
  430. {
  431. if (record == null) return "参数无效。";
  432. record.FixProperties();
  433. record.Updated = ClockUtility.LucidNow;
  434. var structure = null as TableStructure;
  435. try { structure = TableStructure.ParseModel(record); }
  436. catch (Exception exception) { return exception.Message; }
  437. var parameters = structure.CreateDataParameters(record, CreateDataParameter, "_created", "_key");
  438. var sql = GenerateUpdateStatement(structure.Table, record.Key, parameters);
  439. var execute = Execute(sql, parameters);
  440. if (execute.Success && execute.Rows > 0) return TextUtility.EmptyString;
  441. return execute.Error;
  442. }
  443. /// <summary>获取具有指定 Key 的记录。</summary>
  444. public Result<T> Get<T>(string key) where T : Record => Get<T>(key, 0);
  445. /// <summary>获取具有指定 Key 的记录。</summary>
  446. public Result<T> Get<T>(string key, long flag) where T : Record
  447. {
  448. var k = TextUtility.SafeKey(key);
  449. if (TextUtility.IsBlank(k) == false)
  450. {
  451. try
  452. {
  453. var ts = TableStructure.ParseModel(typeof(T));
  454. var f = (flag == 0) ? TextUtility.EmptyString : TextUtility.Merge(" _flag=", flag.ToString(), " and");
  455. var query = (Query)Query(TextUtility.Merge("select * from [", ts.Table, "] where", f, " _key='", k, "' limit 1; "));
  456. var list = query.Fill<T>();
  457. query.Dispose();
  458. if (list.Count > 0) return new Result<T>(list[0]);
  459. }
  460. catch (Exception ex)
  461. {
  462. return new Result<T>(ex);
  463. }
  464. }
  465. return new Result<T>(new Exception("参数无效。"));
  466. }
  467. /// <summary>查询多条记录。</summary>
  468. public Result<List<T>> Query<T>() where T : Record => Query<T>(0);
  469. /// <summary>查询多条记录。</summary>
  470. public Result<List<T>> Query<T>(long flag) where T : Record
  471. {
  472. try
  473. {
  474. var ts = TableStructure.ParseModel(typeof(T));
  475. var f = (flag == 0) ? TextUtility.EmptyString : TextUtility.Merge(" where _flag=", flag.ToString());
  476. var query = Query(TextUtility.Merge("select * from [", ts.Table, "]", f, "; ")) as Query;
  477. var list = query.Fill<T>();
  478. query.Dispose();
  479. return new Result<List<T>>(list);
  480. }
  481. catch (Exception ex)
  482. {
  483. return new Result<List<T>>(ex);
  484. }
  485. }
  486. /// <summary>获取按指定语句查询到的所有记录。</summary>
  487. public Result<List<T>> Query<T>(string sql) where T : Record
  488. {
  489. using (var query = Query(sql) as Query)
  490. {
  491. if (query.Exception == null) return new Result<List<T>>(query.Fill<T>());
  492. else return new Result<List<T>>(query.Exception);
  493. }
  494. }
  495. /// <summary>查询所有有效的 Key 值。</summary>
  496. public Result<List<string>> Keys<T>() where T : Record => Keys<T>(0);
  497. /// <summary>查询所有有效的 Key 值。</summary>
  498. public Result<List<string>> Keys<T>(long flag) where T : Record => Keys(typeof(T), flag);
  499. /// <summary>查询所有有效的 Key 值。</summary>
  500. public Result<List<string>> Keys(Type model) => Keys(model, 0);
  501. /// <summary>查询所有有效的 Key 值。</summary>
  502. public Result<List<string>> Keys(Type model, long flag)
  503. {
  504. if (model != null)
  505. {
  506. try
  507. {
  508. var list = new List<string>();
  509. var ts = TableStructure.ParseModel((Type)model);
  510. var f = (flag == 0) ? TextUtility.EmptyString : TextUtility.Merge(" where _flag=", flag.ToString());
  511. var query = (Query)Query(TextUtility.Merge("select _key from [", ts.Table, "]", f, "; "));
  512. for (var r = 0; r < query.Rows; r++)
  513. {
  514. var cell = TextUtility.Trim(query.Text(r));
  515. if (cell.Length > 0) list.Add(cell);
  516. }
  517. query.Dispose();
  518. return new Result<List<string>>(list);
  519. }
  520. catch (Exception ex)
  521. {
  522. return new Result<List<string>>(ex);
  523. }
  524. }
  525. return new Result<List<string>>(new Exception("参数无效。"));
  526. }
  527. #endregion
  528. #region static
  529. /// <summary>对文本转义,符合 SQL 安全性。可根据字段类型限制 UTF-8 字节数,默认为 0 时不限制字节数。</summary>
  530. public static string Escape(string text, int bytes = 0)
  531. {
  532. if (text.IsEmpty()) return "";
  533. var t = text ?? "";
  534. t = t.Replace("\\", "\\\\");
  535. t = t.Replace("'", "\\'");
  536. t = t.Replace("\n", "\\n");
  537. t = t.Replace("\r", "\\r");
  538. t = t.Replace("\b", "\\b");
  539. t = t.Replace("\t", "\\t");
  540. t = t.Replace("\f", "\\f");
  541. if (bytes > 5)
  542. {
  543. if (t.GetBytes(Encoding.UTF8).Length > bytes)
  544. {
  545. while (true)
  546. {
  547. t = t.Substring(0, t.Length - 1);
  548. if (t.GetBytes(Encoding.UTF8).Length <= (bytes - 4)) break;
  549. }
  550. t = t + " ...";
  551. }
  552. }
  553. return t;
  554. }
  555. private static string GetColumnTypeName(ColumnType type)
  556. {
  557. switch (type)
  558. {
  559. case ColumnType.Binary:
  560. return "blob";
  561. case ColumnType.Integer:
  562. return "integer";
  563. case ColumnType.Float:
  564. return "float";
  565. case ColumnType.VarChar:
  566. case ColumnType.VarChar255:
  567. case ColumnType.VarCharMax:
  568. return "varchar";
  569. case ColumnType.Text:
  570. return "text";
  571. case ColumnType.NVarChar:
  572. case ColumnType.NVarChar255:
  573. case ColumnType.NVarCharMax:
  574. return "nvarchar";
  575. case ColumnType.NText:
  576. return "ntext";
  577. default:
  578. return null;
  579. }
  580. }
  581. private static string GetColumnDeclaration(ColumnAttribute column)
  582. {
  583. var type = TextUtility.EmptyString;
  584. var length = NumberUtility.RestrictValue(column.Length, 0, 255).ToString();
  585. switch (column.Type)
  586. {
  587. case ColumnType.Binary:
  588. type = "blob";
  589. break;
  590. case ColumnType.Integer:
  591. type = "integer";
  592. break;
  593. case ColumnType.Float:
  594. type = "real";
  595. break;
  596. case ColumnType.VarChar:
  597. case ColumnType.VarChar255:
  598. type = TextUtility.Merge("varchar(", length, ")");
  599. break;
  600. case ColumnType.VarCharMax:
  601. type = TextUtility.Merge("varchar(255)");
  602. break;
  603. case ColumnType.Text:
  604. type = TextUtility.Merge("text");
  605. break;
  606. case ColumnType.NVarChar:
  607. case ColumnType.NVarChar255:
  608. type = TextUtility.Merge("nvarchar(", length, ")");
  609. break;
  610. case ColumnType.NVarCharMax:
  611. type = TextUtility.Merge("nvarchar(255)");
  612. break;
  613. case ColumnType.NText:
  614. type = TextUtility.Merge("ntext");
  615. break;
  616. default:
  617. return TextUtility.EmptyString;
  618. }
  619. return TextUtility.Merge("[", (object)column.Field, "] ", type);
  620. }
  621. /// <summary>创建参数。</summary>
  622. /// <exception cref="ArgumentNullException"></exception>
  623. /// <exception cref="InvalidOperationException"></exception>
  624. public static SQLiteParameter CreateDataParameter(Parameter parameter)
  625. {
  626. if (parameter == null) throw new InvalidOperationException("参数无效。");
  627. return CreateDataParameter(parameter.Name, parameter.Type, parameter.Size, parameter.Value);
  628. }
  629. /// <summary>创建参数。</summary>
  630. public static SQLiteParameter CreateDataParameter(string name, ColumnType type, int size, object value)
  631. {
  632. var n = TextUtility.Trim(name);
  633. if (TextUtility.IsBlank(n)) return null;
  634. var t = GetColumnTypeName(type);
  635. var s = size;
  636. switch (type)
  637. {
  638. case ColumnType.VarChar:
  639. s = NumberUtility.RestrictValue(s, 0, 8000);
  640. break;
  641. case ColumnType.NVarChar:
  642. s = NumberUtility.RestrictValue(s, 0, 4000);
  643. break;
  644. case ColumnType.VarChar255:
  645. case ColumnType.VarCharMax:
  646. case ColumnType.NVarChar255:
  647. case ColumnType.NVarCharMax:
  648. s = NumberUtility.RestrictValue(s, 0, 255);
  649. break;
  650. default:
  651. s = 0;
  652. break;
  653. }
  654. var v = value;
  655. if (v is string && v != null && s > 0)
  656. {
  657. v = TextUtility.RestrictLength((string)v, s);
  658. }
  659. var p = new SQLiteParameter();
  660. p.ParameterName = n;
  661. p.TypeName = t;
  662. p.Value = v;
  663. if (s > 0) p.Size = s;
  664. return p;
  665. }
  666. /// <summary>创建参数。</summary>
  667. public static SQLiteParameter CreateDataParameter(string name, string type, int size, object value)
  668. {
  669. var v = value;
  670. if (value is string && value != null && size > 0)
  671. {
  672. v = TextUtility.RestrictLength((string)value, size);
  673. }
  674. var p = new SQLiteParameter();
  675. p.ParameterName = name;
  676. p.TypeName = type;
  677. p.Value = v;
  678. p.Size = size;
  679. return p;
  680. }
  681. /// <summary>创建参数。</summary>
  682. public static SQLiteParameter CreateDataParameter(string name, string type, object value)
  683. {
  684. var p = new SQLiteParameter();
  685. p.ParameterName = name;
  686. p.TypeName = type;
  687. p.Value = value;
  688. return p;
  689. }
  690. /// <summary>备份数据库,返回错误信息。</summary>
  691. public static string Backup(Sqlite source, Sqlite destination)
  692. {
  693. if (source == null) return "SQLite Backup Failed: Invalid Source";
  694. if (destination == null) return "SQLite Backup Failed: Invalid Destination";
  695. if (!source.Connect()) return "SQLite Backup Failed: Invalid Source Connection";
  696. if (!destination.Connect()) return "SQLite Backup Failed: Invalid Destination Connection";
  697. try
  698. {
  699. source._db.BackupDatabase(destination._db, "main", "main", -1, null, 0);
  700. return "";
  701. }
  702. catch (Exception ex)
  703. {
  704. return "SQLite Load Failed: " + ex.Message;
  705. }
  706. }
  707. /// <summary>创建参数。</summary>
  708. public static IDbDataParameter CreateParameter(string field, DbType type, int size, object value)
  709. {
  710. var p = new SQLiteParameter();
  711. p.ParameterName = field;
  712. p.DbType = type;
  713. p.Size = size;
  714. p.Value = value;
  715. return p;
  716. }
  717. /// <summary>创建参数。</summary>
  718. public static IDbDataParameter CreateParameter(string field, DbType type, object value)
  719. {
  720. var p = new SQLiteParameter();
  721. p.ParameterName = field;
  722. p.DbType = type;
  723. p.Value = value;
  724. return p;
  725. }
  726. /// <summary>整理数据库,压缩未使用的空间。</summary>
  727. public const string Vacuum = "vacuum";
  728. /// <summary>内存数据库的地址。</summary>
  729. public const string Memory = ":memory:";
  730. #endregion
  731. #region ORM
  732. private static string GetParameterName(string parameter)
  733. {
  734. var name = TextUtility.AntiInject(parameter, 255);
  735. if (name.StartsWith("@") && name.Length > 1)
  736. {
  737. name = name.Substring(1, name.Length - 1);
  738. }
  739. return name;
  740. }
  741. private static string GetParameterName(IDataParameter parameter)
  742. {
  743. var name = TextUtility.EmptyString;
  744. if (parameter != null)
  745. {
  746. name = GetParameterName(parameter.ParameterName);
  747. }
  748. return name;
  749. }
  750. private static List<string> GetParametersNames(IEnumerable<IDataParameter> parameters)
  751. {
  752. var columns = new List<string>();
  753. if (parameters != null)
  754. {
  755. foreach (var parameter in parameters)
  756. {
  757. var name = GetParameterName(parameter);
  758. var isblank = TextUtility.IsBlank(name);
  759. if (isblank) continue;
  760. columns.Add(name);
  761. }
  762. }
  763. return columns;
  764. }
  765. private static string GenerateInsertStatement(string table, List<string> columns)
  766. {
  767. var r = TextUtility.EmptyString;
  768. var t = TextUtility.AntiInject(table, 255);
  769. if (columns != null && !TextUtility.IsBlank(t))
  770. {
  771. var count = 0;
  772. var names = new List<string>();
  773. var values = new List<string>();
  774. foreach (var column in columns)
  775. {
  776. //names.Add(TextGenerator.Merge("[", column, "]"));
  777. names.Add(TextUtility.Merge(column));
  778. values.Add("@" + column);
  779. count += 1;
  780. }
  781. var sb = new StringBuilder();
  782. if (count > 0)
  783. {
  784. sb.Append("insert into [", t, "](", TextUtility.Join(", ", names), ") ");
  785. sb.Append("values(", TextUtility.Join(", ", values), "); ");
  786. }
  787. r = sb.ToString();
  788. }
  789. return r;
  790. }
  791. /// <summary>生成 INSERT INTO 语句。表名必须有效,无有效参数时将获取空结果。</summary>
  792. /// <exception cref="System.ArgumentException"></exception>
  793. /// <exception cref="System.ArgumentNullException"></exception>
  794. public static string GenerateInsertStatement(string table, IEnumerable<IDataParameter> parameters)
  795. {
  796. if (table == null) throw new ArgumentNullException(nameof(table));
  797. var t = TextUtility.AntiInject(table, 255);
  798. if (TextUtility.IsBlank(t)) throw new ArgumentException("表名无效。", nameof(table));
  799. var cs = GetParametersNames(parameters);
  800. if (cs.Count < 1) return TextUtility.EmptyString;
  801. return GenerateInsertStatement(t, cs);
  802. }
  803. private static string GenerateUpdateStatement(string table, string key, List<string> columns)
  804. {
  805. var result = TextUtility.EmptyString;
  806. var t = TextUtility.AntiInject(table, 255);
  807. var k = TextUtility.AntiInject(key, 255);
  808. if (columns != null && !TextUtility.IsBlank(t) && !TextUtility.IsBlank(k))
  809. {
  810. var items = new List<string>();
  811. foreach (var column in columns)
  812. {
  813. items.Add(TextUtility.Merge("[", column, "]=@", column));
  814. }
  815. if (items.Count > 0)
  816. {
  817. result = TextUtility.Merge("update [", t, "] set ", TextUtility.Join(", ", items), " where [_key]='", k, "'; ");
  818. }
  819. }
  820. return result;
  821. }
  822. /// <summary>生成 UPDATE 语句,键字段名为“_key”。表名必须有效,键值必须有效,无有效参数时将获取空结果。</summary>
  823. /// <exception cref="System.ArgumentException"></exception>
  824. /// <exception cref="System.ArgumentNullException"></exception>
  825. public static string GenerateUpdateStatement(string table, string key, IEnumerable<IDataParameter> parameters)
  826. {
  827. if (table == null) throw new ArgumentNullException("argTable");
  828. var t = TextUtility.AntiInject(table, 255);
  829. if (TextUtility.IsBlank(t)) throw new ArgumentException("表名无效。", nameof(table));
  830. if (key == null) throw new ArgumentNullException("argKey");
  831. var k = TextUtility.AntiInject(key, 255);
  832. if (TextUtility.IsBlank(k)) throw new ArgumentException("键值无效。", nameof(key));
  833. var columns = GetParametersNames(parameters);
  834. if (columns.Count < 1) return TextUtility.EmptyString;
  835. return GenerateUpdateStatement(t, k, columns);
  836. }
  837. #endregion
  838. }
  839. }
  840. #endif